omniagent 0.1.6 → 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.
- package/README.md +25 -1
- package/dist/claude-Dmv_YFKX.js +146 -0
- package/dist/cli.js +1566 -12
- package/dist/codex-Cl1dWwMk.js +274 -0
- package/dist/gemini-CskI3Qjp.js +168 -0
- package/dist/pty-CZBSAJzE.js +362 -0
- package/package.json +3 -1
- package/CLAUDE.md +0 -68
- package/CONTRIBUTING.md +0 -56
- package/biome.json +0 -41
- package/tasks.md +0 -25
- package/tsconfig.json +0 -13
- package/vite.config.ts +0 -22
- package/vitest.config.ts +0 -10
package/dist/cli.js
CHANGED
|
@@ -234,8 +234,9 @@ function buildValidationError(resolution, status, message) {
|
|
|
234
234
|
errorMessage: message
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
|
-
async function validateAgentsDir(repoRoot, agentsDir) {
|
|
237
|
+
async function validateAgentsDir(repoRoot, agentsDir, options = {}) {
|
|
238
238
|
const resolution = resolveAgentsDir(repoRoot, agentsDir);
|
|
239
|
+
const requireWrite = options.requireWrite ?? true;
|
|
239
240
|
const buildNotDirectoryError = () => buildValidationError(
|
|
240
241
|
resolution,
|
|
241
242
|
"notDirectory",
|
|
@@ -269,14 +270,16 @@ async function validateAgentsDir(repoRoot, agentsDir) {
|
|
|
269
270
|
return buildNotDirectoryError();
|
|
270
271
|
}
|
|
271
272
|
try {
|
|
272
|
-
|
|
273
|
+
const requiredAccess = constants.R_OK | constants.X_OK | (requireWrite ? constants.W_OK : 0);
|
|
274
|
+
await access(resolution.resolvedPath, requiredAccess);
|
|
273
275
|
} catch (error) {
|
|
274
276
|
const code = error.code;
|
|
275
277
|
if (code === "EACCES" || code === "EPERM") {
|
|
278
|
+
const requirement = requireWrite ? "readable, writable, or searchable" : "readable or searchable";
|
|
276
279
|
return buildValidationError(
|
|
277
280
|
resolution,
|
|
278
281
|
"permissionDenied",
|
|
279
|
-
`Agents directory is not
|
|
282
|
+
`Agents directory is not ${requirement}: ${resolution.resolvedPath}. Check permissions or choose another directory.`
|
|
280
283
|
);
|
|
281
284
|
}
|
|
282
285
|
throw error;
|
|
@@ -1308,6 +1311,20 @@ const claudeTarget = {
|
|
|
1308
1311
|
instructions: {
|
|
1309
1312
|
filename: "CLAUDE.md"
|
|
1310
1313
|
}
|
|
1314
|
+
},
|
|
1315
|
+
usage: {
|
|
1316
|
+
windows: ["hourly", "weekly"],
|
|
1317
|
+
launch: {
|
|
1318
|
+
command: "claude",
|
|
1319
|
+
// Haiku keeps the interactive usage probe on Claude's lowest-cost model family.
|
|
1320
|
+
args: ["--model", "haiku"],
|
|
1321
|
+
cheapModel: "haiku",
|
|
1322
|
+
timeoutMs: 6e4
|
|
1323
|
+
},
|
|
1324
|
+
extract: async (context) => {
|
|
1325
|
+
const { extractClaudeUsage } = await import("./claude-Dmv_YFKX.js");
|
|
1326
|
+
return extractClaudeUsage(context);
|
|
1327
|
+
}
|
|
1311
1328
|
}
|
|
1312
1329
|
};
|
|
1313
1330
|
const codexTarget = {
|
|
@@ -1367,6 +1384,27 @@ const codexTarget = {
|
|
|
1367
1384
|
filename: "AGENTS.md",
|
|
1368
1385
|
group: "agents"
|
|
1369
1386
|
}
|
|
1387
|
+
},
|
|
1388
|
+
usage: {
|
|
1389
|
+
windows: ["hourly", "weekly"],
|
|
1390
|
+
launch: {
|
|
1391
|
+
command: "codex",
|
|
1392
|
+
// Usage probing does not need plugins/apps; disabling them avoids MCP startup work.
|
|
1393
|
+
args: [
|
|
1394
|
+
"--no-alt-screen",
|
|
1395
|
+
"--disable",
|
|
1396
|
+
"apps",
|
|
1397
|
+
"--disable",
|
|
1398
|
+
"computer_use",
|
|
1399
|
+
"--disable",
|
|
1400
|
+
"plugins"
|
|
1401
|
+
],
|
|
1402
|
+
timeoutMs: 6e4
|
|
1403
|
+
},
|
|
1404
|
+
extract: async (context) => {
|
|
1405
|
+
const { extractCodexUsage } = await import("./codex-Cl1dWwMk.js");
|
|
1406
|
+
return extractCodexUsage(context);
|
|
1407
|
+
}
|
|
1370
1408
|
}
|
|
1371
1409
|
};
|
|
1372
1410
|
const FRONTMATTER_MARKER$1 = "---";
|
|
@@ -1558,6 +1596,19 @@ const geminiTarget = {
|
|
|
1558
1596
|
instructions: {
|
|
1559
1597
|
filename: "GEMINI.md"
|
|
1560
1598
|
}
|
|
1599
|
+
},
|
|
1600
|
+
usage: {
|
|
1601
|
+
windows: ["model"],
|
|
1602
|
+
launch: {
|
|
1603
|
+
command: "gemini",
|
|
1604
|
+
// /model inspection does not need a model override; Gemini requires session-scoped trust.
|
|
1605
|
+
args: ["--skip-trust"],
|
|
1606
|
+
timeoutMs: 7e4
|
|
1607
|
+
},
|
|
1608
|
+
extract: async (context) => {
|
|
1609
|
+
const { extractGeminiUsage } = await import("./gemini-CskI3Qjp.js");
|
|
1610
|
+
return extractGeminiUsage(context);
|
|
1611
|
+
}
|
|
1561
1612
|
}
|
|
1562
1613
|
};
|
|
1563
1614
|
const BUILTIN_TARGETS = [
|
|
@@ -2513,6 +2564,39 @@ function validateCliDefinition(cli, label, errors) {
|
|
|
2513
2564
|
errors.push(`${label}.translate must be a function when provided.`);
|
|
2514
2565
|
}
|
|
2515
2566
|
}
|
|
2567
|
+
function validateUsageDefinition(usage, label, errors) {
|
|
2568
|
+
if (usage === void 0) {
|
|
2569
|
+
return;
|
|
2570
|
+
}
|
|
2571
|
+
if (!isPlainObject(usage)) {
|
|
2572
|
+
errors.push(`${label} must be an object.`);
|
|
2573
|
+
return;
|
|
2574
|
+
}
|
|
2575
|
+
validateStringArray(usage.windows, `${label}.windows`, errors);
|
|
2576
|
+
if (usage.launch !== void 0) {
|
|
2577
|
+
if (!isPlainObject(usage.launch)) {
|
|
2578
|
+
errors.push(`${label}.launch must be an object.`);
|
|
2579
|
+
} else {
|
|
2580
|
+
if (usage.launch.command !== void 0 && normalizeString(usage.launch.command) === null) {
|
|
2581
|
+
errors.push(`${label}.launch.command must be a non-empty string when provided.`);
|
|
2582
|
+
}
|
|
2583
|
+
if (usage.launch.args !== void 0) {
|
|
2584
|
+
validateStringArray(usage.launch.args, `${label}.launch.args`, errors, {
|
|
2585
|
+
allowEmpty: true
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
if (usage.launch.timeoutMs !== void 0 && (typeof usage.launch.timeoutMs !== "number" || !Number.isFinite(usage.launch.timeoutMs) || usage.launch.timeoutMs <= 0)) {
|
|
2589
|
+
errors.push(`${label}.launch.timeoutMs must be a positive number when provided.`);
|
|
2590
|
+
}
|
|
2591
|
+
if (usage.launch.cheapModel !== void 0 && normalizeString(usage.launch.cheapModel) === null) {
|
|
2592
|
+
errors.push(`${label}.launch.cheapModel must be a non-empty string when provided.`);
|
|
2593
|
+
}
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
if (typeof usage.extract !== "function") {
|
|
2597
|
+
errors.push(`${label}.extract must be a function.`);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2516
2600
|
function validateTemplate(value, label, allowed, errors) {
|
|
2517
2601
|
if (typeof value === "function") {
|
|
2518
2602
|
return;
|
|
@@ -2745,6 +2829,7 @@ function validateTargetConfig(options) {
|
|
|
2745
2829
|
}
|
|
2746
2830
|
validateOutputs(entry2.outputs, `${label}.outputs`, errors);
|
|
2747
2831
|
validateCliDefinition(entry2.cli, `${label}.cli`, errors);
|
|
2832
|
+
validateUsageDefinition(entry2.usage, `${label}.usage`, errors);
|
|
2748
2833
|
}
|
|
2749
2834
|
}
|
|
2750
2835
|
}
|
|
@@ -2771,6 +2856,19 @@ function cloneOutputs(outputs) {
|
|
|
2771
2856
|
function cloneCli(cli) {
|
|
2772
2857
|
return cli ? { ...cli } : void 0;
|
|
2773
2858
|
}
|
|
2859
|
+
function cloneUsage(usage) {
|
|
2860
|
+
if (!usage) {
|
|
2861
|
+
return void 0;
|
|
2862
|
+
}
|
|
2863
|
+
return {
|
|
2864
|
+
...usage,
|
|
2865
|
+
windows: [...usage.windows],
|
|
2866
|
+
launch: usage.launch ? {
|
|
2867
|
+
...usage.launch,
|
|
2868
|
+
args: usage.launch.args ? [...usage.launch.args] : void 0
|
|
2869
|
+
} : void 0
|
|
2870
|
+
};
|
|
2871
|
+
}
|
|
2774
2872
|
function mergeOutputs(base, override) {
|
|
2775
2873
|
const merged = { ...cloneOutputs(base) };
|
|
2776
2874
|
if (!override) {
|
|
@@ -2826,6 +2924,7 @@ function resolveTargets(options) {
|
|
|
2826
2924
|
aliases: builtIn.aliases ?? [],
|
|
2827
2925
|
outputs: cloneOutputs(builtIn.outputs),
|
|
2828
2926
|
cli: cloneCli(builtIn.cli),
|
|
2927
|
+
usage: cloneUsage(builtIn.usage),
|
|
2829
2928
|
hooks: builtIn.hooks,
|
|
2830
2929
|
isBuiltIn: true,
|
|
2831
2930
|
isCustomized: false
|
|
@@ -2841,7 +2940,8 @@ function resolveTargets(options) {
|
|
|
2841
2940
|
displayName: customTarget.displayName ?? inherited?.displayName ?? customTarget.id,
|
|
2842
2941
|
aliases: customTarget.aliases ?? inherited?.aliases ?? [],
|
|
2843
2942
|
outputs: mergedOutputs,
|
|
2844
|
-
cli: customTarget.cli ?? inherited?.cli,
|
|
2943
|
+
cli: cloneCli(customTarget.cli ?? inherited?.cli),
|
|
2944
|
+
usage: cloneUsage(customTarget.usage ?? inherited?.usage),
|
|
2845
2945
|
hooks: customTarget.hooks ?? inherited?.hooks,
|
|
2846
2946
|
isBuiltIn: true,
|
|
2847
2947
|
isCustomized: true
|
|
@@ -2854,6 +2954,7 @@ function resolveTargets(options) {
|
|
|
2854
2954
|
aliases: customTarget.aliases ?? [],
|
|
2855
2955
|
outputs: cloneOutputs(customTarget.outputs),
|
|
2856
2956
|
cli: cloneCli(customTarget.cli),
|
|
2957
|
+
usage: cloneUsage(customTarget.usage),
|
|
2857
2958
|
hooks: customTarget.hooks,
|
|
2858
2959
|
isBuiltIn: true,
|
|
2859
2960
|
isCustomized: true
|
|
@@ -2873,7 +2974,8 @@ function resolveTargets(options) {
|
|
|
2873
2974
|
displayName: target.displayName ?? inherited?.displayName ?? target.id,
|
|
2874
2975
|
aliases: target.aliases ?? inherited?.aliases ?? [],
|
|
2875
2976
|
outputs: mergedOutputs,
|
|
2876
|
-
cli: target.cli ?? inherited?.cli,
|
|
2977
|
+
cli: cloneCli(target.cli ?? inherited?.cli),
|
|
2978
|
+
usage: cloneUsage(target.usage ?? inherited?.usage),
|
|
2877
2979
|
hooks: target.hooks ?? inherited?.hooks,
|
|
2878
2980
|
isBuiltIn: false,
|
|
2879
2981
|
isCustomized: true
|
|
@@ -2898,6 +3000,26 @@ function resolveTargets(options) {
|
|
|
2898
3000
|
disabledTargets
|
|
2899
3001
|
};
|
|
2900
3002
|
}
|
|
3003
|
+
const PROFILE_SCHEMA_URL = "https://raw.githubusercontent.com/JoeRoddy/omniagent/master/schemas/profile.v1.json";
|
|
3004
|
+
const ANSI_GRAY = "\x1B[90m";
|
|
3005
|
+
const ANSI_RESET_FOREGROUND = "\x1B[39m";
|
|
3006
|
+
const PROFILE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
3007
|
+
const STARTER_PROFILE = {
|
|
3008
|
+
$schema: PROFILE_SCHEMA_URL,
|
|
3009
|
+
description: "",
|
|
3010
|
+
targets: {},
|
|
3011
|
+
enable: {
|
|
3012
|
+
skills: [],
|
|
3013
|
+
subagents: [],
|
|
3014
|
+
commands: []
|
|
3015
|
+
},
|
|
3016
|
+
disable: {
|
|
3017
|
+
skills: [],
|
|
3018
|
+
subagents: [],
|
|
3019
|
+
commands: []
|
|
3020
|
+
},
|
|
3021
|
+
variables: {}
|
|
3022
|
+
};
|
|
2901
3023
|
async function resolveRepoAndAgentsDir(argv) {
|
|
2902
3024
|
const startDir = process.cwd();
|
|
2903
3025
|
const repoRoot = await findRepoRoot(startDir);
|
|
@@ -2931,6 +3053,122 @@ function formatAnnotations(entry2) {
|
|
|
2931
3053
|
}
|
|
2932
3054
|
return annotations;
|
|
2933
3055
|
}
|
|
3056
|
+
function validateProfileNamePart(name) {
|
|
3057
|
+
if (!PROFILE_NAME_PATTERN.test(name)) {
|
|
3058
|
+
return "Profile names may only contain letters, numbers, dots, underscores, and hyphens, and must start with a letter or number.";
|
|
3059
|
+
}
|
|
3060
|
+
return null;
|
|
3061
|
+
}
|
|
3062
|
+
function parseInitProfileTarget(name) {
|
|
3063
|
+
if (name.endsWith(".local")) {
|
|
3064
|
+
const profileName = name.slice(0, -".local".length);
|
|
3065
|
+
const issue2 = validateProfileNamePart(profileName);
|
|
3066
|
+
if (issue2) {
|
|
3067
|
+
return { error: issue2 };
|
|
3068
|
+
}
|
|
3069
|
+
if (profileName.endsWith(".local")) {
|
|
3070
|
+
return { error: 'Profile names cannot end with ".local.local".' };
|
|
3071
|
+
}
|
|
3072
|
+
return {
|
|
3073
|
+
profileName,
|
|
3074
|
+
isLocal: true
|
|
3075
|
+
};
|
|
3076
|
+
}
|
|
3077
|
+
const issue = validateProfileNamePart(name);
|
|
3078
|
+
if (issue) {
|
|
3079
|
+
return { error: issue };
|
|
3080
|
+
}
|
|
3081
|
+
return {
|
|
3082
|
+
profileName: name,
|
|
3083
|
+
isLocal: false
|
|
3084
|
+
};
|
|
3085
|
+
}
|
|
3086
|
+
function colorsEnabled() {
|
|
3087
|
+
if (process.env.NO_COLOR !== void 0) {
|
|
3088
|
+
return false;
|
|
3089
|
+
}
|
|
3090
|
+
const forced = process.env.FORCE_COLOR;
|
|
3091
|
+
if (forced !== void 0) {
|
|
3092
|
+
return forced !== "0" && forced.toLowerCase() !== "false";
|
|
3093
|
+
}
|
|
3094
|
+
return Boolean(process.stdout.isTTY);
|
|
3095
|
+
}
|
|
3096
|
+
function findLineCommentStart(line) {
|
|
3097
|
+
let inString = false;
|
|
3098
|
+
let escaped = false;
|
|
3099
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
3100
|
+
const char = line[index];
|
|
3101
|
+
if (escaped) {
|
|
3102
|
+
escaped = false;
|
|
3103
|
+
continue;
|
|
3104
|
+
}
|
|
3105
|
+
if (char === "\\" && inString) {
|
|
3106
|
+
escaped = true;
|
|
3107
|
+
continue;
|
|
3108
|
+
}
|
|
3109
|
+
if (char === '"') {
|
|
3110
|
+
inString = !inString;
|
|
3111
|
+
continue;
|
|
3112
|
+
}
|
|
3113
|
+
if (!inString && char === "/" && line[index + 1] === "/") {
|
|
3114
|
+
return index;
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
return null;
|
|
3118
|
+
}
|
|
3119
|
+
function colorizeGuideComments(text) {
|
|
3120
|
+
if (!colorsEnabled()) {
|
|
3121
|
+
return text;
|
|
3122
|
+
}
|
|
3123
|
+
return text.split("\n").map((line) => {
|
|
3124
|
+
const commentStart = findLineCommentStart(line);
|
|
3125
|
+
if (commentStart === null) {
|
|
3126
|
+
return line;
|
|
3127
|
+
}
|
|
3128
|
+
return `${line.slice(0, commentStart)}${ANSI_GRAY}${line.slice(commentStart)}${ANSI_RESET_FOREGROUND}`;
|
|
3129
|
+
}).join("\n");
|
|
3130
|
+
}
|
|
3131
|
+
function initGuide(target, displayPath) {
|
|
3132
|
+
const label = target.isLocal ? `Created local profile "${target.profileName}" at ${displayPath}.` : `Created profile "${target.profileName}" at ${displayPath}.`;
|
|
3133
|
+
const localHint = target.isLocal ? `
|
|
3134
|
+
Use profile name "${target.profileName}" when syncing; ".local" is only the file suffix.
|
|
3135
|
+
` : "";
|
|
3136
|
+
return colorizeGuideComments(`${label}${localHint}
|
|
3137
|
+
|
|
3138
|
+
Profile files must be valid JSON. This commented version is just a guide:
|
|
3139
|
+
|
|
3140
|
+
{
|
|
3141
|
+
"$schema": "${PROFILE_SCHEMA_URL}",
|
|
3142
|
+
|
|
3143
|
+
"description": "shown in \`omniagent profiles\`",
|
|
3144
|
+
|
|
3145
|
+
"targets": {
|
|
3146
|
+
"claude": { "enabled": true }, // includes Claude; overrides an earlier profile setting it false
|
|
3147
|
+
"gemini": { "enabled": false } // skips Gemini for this profile
|
|
3148
|
+
},
|
|
3149
|
+
|
|
3150
|
+
"enable": { // names/globs to include; also opts in items marked enabled:false
|
|
3151
|
+
"skills": ["code-review"],
|
|
3152
|
+
"subagents": ["reviewer"],
|
|
3153
|
+
"commands": []
|
|
3154
|
+
},
|
|
3155
|
+
|
|
3156
|
+
"disable": { // names/globs to exclude after enable rules
|
|
3157
|
+
"skills": [],
|
|
3158
|
+
"subagents": [],
|
|
3159
|
+
"commands": ["*-legacy"]
|
|
3160
|
+
},
|
|
3161
|
+
|
|
3162
|
+
// https://github.com/JoeRoddy/omniagent/blob/master/docs/templating.md
|
|
3163
|
+
"variables": {
|
|
3164
|
+
"REVIEW_STYLE": "thorough" // replaces {{REVIEW_STYLE}} in synced files
|
|
3165
|
+
}
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
Try it:
|
|
3169
|
+
omniagent profiles show ${target.profileName}
|
|
3170
|
+
omniagent sync --profile ${target.profileName}`);
|
|
3171
|
+
}
|
|
2934
3172
|
async function loadProfileValidationCatalog(repoRoot, agentsDir) {
|
|
2935
3173
|
const { config } = await loadTargetConfig({ repoRoot, agentsDir });
|
|
2936
3174
|
const validation = validateTargetConfig({ config, builtIns: BUILTIN_TARGETS });
|
|
@@ -3016,6 +3254,70 @@ function collectProfileReferenceIssues(profileName, resolvedProfile, catalog) {
|
|
|
3016
3254
|
}
|
|
3017
3255
|
return issues;
|
|
3018
3256
|
}
|
|
3257
|
+
const initSubcommand = {
|
|
3258
|
+
command: "init <name>",
|
|
3259
|
+
describe: "Create a new sync profile",
|
|
3260
|
+
builder: (yargs2) => yargs2.positional("name", {
|
|
3261
|
+
type: "string",
|
|
3262
|
+
demandOption: true,
|
|
3263
|
+
describe: "Profile name"
|
|
3264
|
+
}).option("agentsDir", {
|
|
3265
|
+
type: "string",
|
|
3266
|
+
describe: "Override the agents directory",
|
|
3267
|
+
defaultDescription: DEFAULT_AGENTS_DIR
|
|
3268
|
+
}),
|
|
3269
|
+
handler: async (argv) => {
|
|
3270
|
+
const typed = argv;
|
|
3271
|
+
const initTarget = parseInitProfileTarget(typed.name);
|
|
3272
|
+
if ("error" in initTarget) {
|
|
3273
|
+
console.error(`Error: ${initTarget.error}`);
|
|
3274
|
+
process.exit(1);
|
|
3275
|
+
return;
|
|
3276
|
+
}
|
|
3277
|
+
const resolved = await resolveRepoAndAgentsDir(typed);
|
|
3278
|
+
if (!resolved) return;
|
|
3279
|
+
if (initTarget.isLocal) {
|
|
3280
|
+
const existingDedicatedPath = profileLocalDedicatedPath(
|
|
3281
|
+
resolved.repoRoot,
|
|
3282
|
+
initTarget.profileName,
|
|
3283
|
+
resolved.agentsDir
|
|
3284
|
+
);
|
|
3285
|
+
const inspected = await inspectProfileFiles(
|
|
3286
|
+
resolved.repoRoot,
|
|
3287
|
+
initTarget.profileName,
|
|
3288
|
+
resolved.agentsDir
|
|
3289
|
+
);
|
|
3290
|
+
if (inspected.localDedicated.exists) {
|
|
3291
|
+
const displayPath2 = path.relative(resolved.repoRoot, existingDedicatedPath).split(path.sep).join("/");
|
|
3292
|
+
console.error(
|
|
3293
|
+
`Error: Local profile "${initTarget.profileName}" already exists at ${displayPath2}.`
|
|
3294
|
+
);
|
|
3295
|
+
process.exit(1);
|
|
3296
|
+
return;
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
const targetPath = initTarget.isLocal ? profileLocalSiblingPath(resolved.repoRoot, initTarget.profileName, resolved.agentsDir) : profileSharedPath(resolved.repoRoot, initTarget.profileName, resolved.agentsDir);
|
|
3300
|
+
const displayPath = path.relative(resolved.repoRoot, targetPath).split(path.sep).join("/");
|
|
3301
|
+
const starterContents = `${JSON.stringify(STARTER_PROFILE, null, 2)}
|
|
3302
|
+
`;
|
|
3303
|
+
try {
|
|
3304
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
3305
|
+
await writeFile(targetPath, starterContents, { encoding: "utf8", flag: "wx" });
|
|
3306
|
+
} catch (error) {
|
|
3307
|
+
const code = error.code;
|
|
3308
|
+
if (code === "EEXIST") {
|
|
3309
|
+
const label = initTarget.isLocal ? "Local profile" : "Profile";
|
|
3310
|
+
console.error(
|
|
3311
|
+
`Error: ${label} "${initTarget.profileName}" already exists at ${displayPath}.`
|
|
3312
|
+
);
|
|
3313
|
+
process.exit(1);
|
|
3314
|
+
return;
|
|
3315
|
+
}
|
|
3316
|
+
throw error;
|
|
3317
|
+
}
|
|
3318
|
+
console.log(initGuide(initTarget, displayPath));
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
3019
3321
|
const listSubcommand = {
|
|
3020
3322
|
command: "$0",
|
|
3021
3323
|
describe: "List available sync profiles",
|
|
@@ -3191,7 +3493,7 @@ const validateSubcommand = {
|
|
|
3191
3493
|
const profilesCommand = {
|
|
3192
3494
|
command: "profiles",
|
|
3193
3495
|
describe: "Inspect and validate sync profiles",
|
|
3194
|
-
builder: (yargs2) => yargs2.command(listSubcommand).command(showSubcommand).command(validateSubcommand).demandCommand(0).strictCommands(),
|
|
3496
|
+
builder: (yargs2) => yargs2.command(listSubcommand).command(initSubcommand).command(showSubcommand).command(validateSubcommand).demandCommand(0).strictCommands(),
|
|
3195
3497
|
handler: () => {
|
|
3196
3498
|
}
|
|
3197
3499
|
};
|
|
@@ -8166,7 +8468,7 @@ const DEFAULT_SUPPORTED_TARGETS = BUILTIN_TARGETS.map((target) => target.id).joi
|
|
|
8166
8468
|
const LOCAL_CATEGORIES = ["skills", "commands", "agents", "instructions"];
|
|
8167
8469
|
const LOCAL_CATEGORY_SET = new Set(LOCAL_CATEGORIES);
|
|
8168
8470
|
const utf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
8169
|
-
function parseList(value) {
|
|
8471
|
+
function parseList$1(value) {
|
|
8170
8472
|
if (!value) {
|
|
8171
8473
|
return [];
|
|
8172
8474
|
}
|
|
@@ -8235,7 +8537,7 @@ function parseExcludeLocal(value) {
|
|
|
8235
8537
|
if (value === true) {
|
|
8236
8538
|
return { excludeAll: true, categories: new Set(LOCAL_CATEGORIES), invalid: [] };
|
|
8237
8539
|
}
|
|
8238
|
-
const list = parseList(value);
|
|
8540
|
+
const list = parseList$1(value);
|
|
8239
8541
|
if (list.length === 0) {
|
|
8240
8542
|
return { excludeAll: true, categories: new Set(LOCAL_CATEGORIES), invalid: [] };
|
|
8241
8543
|
}
|
|
@@ -9253,8 +9555,8 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
9253
9555
|
),
|
|
9254
9556
|
handler: async (argv) => {
|
|
9255
9557
|
try {
|
|
9256
|
-
const skipList = parseList(argv.skip);
|
|
9257
|
-
const onlyList = parseList(argv.only);
|
|
9558
|
+
const skipList = parseList$1(argv.skip);
|
|
9559
|
+
const onlyList = parseList$1(argv.only);
|
|
9258
9560
|
const excludeLocalSelection = parseExcludeLocal(argv.excludeLocal);
|
|
9259
9561
|
if (excludeLocalSelection.invalid.length > 0) {
|
|
9260
9562
|
const invalidList = excludeLocalSelection.invalid.join(", ");
|
|
@@ -10009,6 +10311,1252 @@ Config: auto-discovered as omniagent.config.(ts|mts|cts|js|mjs|cjs) in the agent
|
|
|
10009
10311
|
}
|
|
10010
10312
|
}
|
|
10011
10313
|
};
|
|
10314
|
+
const MONTHS = /* @__PURE__ */ new Map([
|
|
10315
|
+
["jan", 0],
|
|
10316
|
+
["january", 0],
|
|
10317
|
+
["feb", 1],
|
|
10318
|
+
["february", 1],
|
|
10319
|
+
["mar", 2],
|
|
10320
|
+
["march", 2],
|
|
10321
|
+
["apr", 3],
|
|
10322
|
+
["april", 3],
|
|
10323
|
+
["may", 4],
|
|
10324
|
+
["jun", 5],
|
|
10325
|
+
["june", 5],
|
|
10326
|
+
["jul", 6],
|
|
10327
|
+
["july", 6],
|
|
10328
|
+
["aug", 7],
|
|
10329
|
+
["august", 7],
|
|
10330
|
+
["sep", 8],
|
|
10331
|
+
["sept", 8],
|
|
10332
|
+
["september", 8],
|
|
10333
|
+
["oct", 9],
|
|
10334
|
+
["october", 9],
|
|
10335
|
+
["nov", 10],
|
|
10336
|
+
["november", 10],
|
|
10337
|
+
["dec", 11],
|
|
10338
|
+
["december", 11]
|
|
10339
|
+
]);
|
|
10340
|
+
const ESCAPE_CHARACTER = String.fromCharCode(27);
|
|
10341
|
+
const BELL_CHARACTER = String.fromCharCode(7);
|
|
10342
|
+
const OSC_SEQUENCE_PATTERN = new RegExp(
|
|
10343
|
+
`${escapeRegExp(ESCAPE_CHARACTER)}\\][\\s\\S]*?(?:${escapeRegExp(BELL_CHARACTER)}|${escapeRegExp(ESCAPE_CHARACTER)}\\\\)`,
|
|
10344
|
+
"g"
|
|
10345
|
+
);
|
|
10346
|
+
const CSI_SEQUENCE_PATTERN = new RegExp(
|
|
10347
|
+
`${escapeRegExp(ESCAPE_CHARACTER)}\\[[0-?]*[ -/]*[@-~]`,
|
|
10348
|
+
"g"
|
|
10349
|
+
);
|
|
10350
|
+
const CHARSET_SEQUENCE_PATTERN = new RegExp(
|
|
10351
|
+
`${escapeRegExp(ESCAPE_CHARACTER)}[()][A-Za-z0-9]`,
|
|
10352
|
+
"g"
|
|
10353
|
+
);
|
|
10354
|
+
const MODE_SEQUENCE_PATTERN = new RegExp(`${escapeRegExp(ESCAPE_CHARACTER)}[=>]`, "g");
|
|
10355
|
+
function makeUsageLimit(options) {
|
|
10356
|
+
const agent = options.agent ?? options.targetId;
|
|
10357
|
+
const resetText = emptyToNull(options.resetText);
|
|
10358
|
+
const window = normalizeUsageWindow(options.window);
|
|
10359
|
+
return {
|
|
10360
|
+
id: [options.targetId, options.scope, window, options.modelId].filter(Boolean).join("."),
|
|
10361
|
+
targetId: options.targetId,
|
|
10362
|
+
agent,
|
|
10363
|
+
scope: options.scope,
|
|
10364
|
+
window,
|
|
10365
|
+
label: options.label,
|
|
10366
|
+
modelId: options.modelId,
|
|
10367
|
+
modelLabel: options.modelLabel,
|
|
10368
|
+
percentUsed: options.percentUsed,
|
|
10369
|
+
percentRemaining: options.percentRemaining,
|
|
10370
|
+
resetAt: parseResetAt(resetText, {
|
|
10371
|
+
now: options.now,
|
|
10372
|
+
sourceTimeZone: options.resetSourceTimeZone ?? "local"
|
|
10373
|
+
}),
|
|
10374
|
+
resetText,
|
|
10375
|
+
raw: options.raw ?? ""
|
|
10376
|
+
};
|
|
10377
|
+
}
|
|
10378
|
+
function parsePercentUsed(value) {
|
|
10379
|
+
return parsePercent(value, /(\d+(?:\.\d+)?)\s*%\s*used/i);
|
|
10380
|
+
}
|
|
10381
|
+
function parsePercentRemaining(value) {
|
|
10382
|
+
return parsePercent(value, /(\d+(?:\.\d+)?)\s*%\s*(?:left|remaining)/i);
|
|
10383
|
+
}
|
|
10384
|
+
function parsePercent(value, pattern = /(\d+(?:\.\d+)?)\s*%/) {
|
|
10385
|
+
const match = pattern.exec(value ?? "");
|
|
10386
|
+
if (match == null) {
|
|
10387
|
+
return null;
|
|
10388
|
+
}
|
|
10389
|
+
return Number(match[1]);
|
|
10390
|
+
}
|
|
10391
|
+
function parseResetText(value) {
|
|
10392
|
+
const match = /\((resets[^)]*)\)/i.exec(value ?? "");
|
|
10393
|
+
return match == null ? null : match[1].trim();
|
|
10394
|
+
}
|
|
10395
|
+
function normalizeUsageWindow(window) {
|
|
10396
|
+
const normalized = window.trim().toLowerCase();
|
|
10397
|
+
if (normalized === "5h" || normalized === "five_hour" || normalized === "five-hour" || normalized === "session" || normalized === "hourly") {
|
|
10398
|
+
return "hourly";
|
|
10399
|
+
}
|
|
10400
|
+
if (normalized === "week" || normalized === "current_week" || normalized === "weekly") {
|
|
10401
|
+
return "weekly";
|
|
10402
|
+
}
|
|
10403
|
+
if (normalized === "model") {
|
|
10404
|
+
return "model";
|
|
10405
|
+
}
|
|
10406
|
+
return normalized;
|
|
10407
|
+
}
|
|
10408
|
+
function cleanControlOutput(raw) {
|
|
10409
|
+
return raw.replace(OSC_SEQUENCE_PATTERN, "").replace(CSI_SEQUENCE_PATTERN, "").replace(CHARSET_SEQUENCE_PATTERN, "").replace(MODE_SEQUENCE_PATTERN, "").replace(/\r/g, "\n").split("\n").map((line) => line.replace(/[ \t]+$/g, "")).join("\n");
|
|
10410
|
+
}
|
|
10411
|
+
function compactLines(text) {
|
|
10412
|
+
return text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
10413
|
+
}
|
|
10414
|
+
function parseResetAt(resetText, options = {}) {
|
|
10415
|
+
const now = options.now ?? /* @__PURE__ */ new Date();
|
|
10416
|
+
const sourceTimeZone = options.sourceTimeZone ?? "local";
|
|
10417
|
+
const text = normalizeResetText(resetText);
|
|
10418
|
+
if (!text) {
|
|
10419
|
+
return null;
|
|
10420
|
+
}
|
|
10421
|
+
return parseHourMinuteOnDayMonth(text, now, sourceTimeZone) ?? parseMonthDayAtTime(text, now, sourceTimeZone) ?? parseDayMonthAtTime(text, now, sourceTimeZone) ?? parseTimeOnly(text, now, sourceTimeZone);
|
|
10422
|
+
}
|
|
10423
|
+
function parseHourMinuteOnDayMonth(text, now, sourceTimeZone) {
|
|
10424
|
+
const match = /^(\d{1,2}):(\d{2})\s+on\s+(\d{1,2})\s+([A-Za-z]+)$/i.exec(text);
|
|
10425
|
+
if (match == null) {
|
|
10426
|
+
return null;
|
|
10427
|
+
}
|
|
10428
|
+
const [, hour, minute, day, monthName] = match;
|
|
10429
|
+
const month = parseMonth(monthName);
|
|
10430
|
+
if (month == null) {
|
|
10431
|
+
return null;
|
|
10432
|
+
}
|
|
10433
|
+
return buildFutureDate(now, sourceTimeZone, {
|
|
10434
|
+
month,
|
|
10435
|
+
day: Number(day),
|
|
10436
|
+
hour: Number(hour),
|
|
10437
|
+
minute: Number(minute)
|
|
10438
|
+
});
|
|
10439
|
+
}
|
|
10440
|
+
function parseMonthDayAtTime(text, now, sourceTimeZone) {
|
|
10441
|
+
const match = /^([A-Za-z]+)\s+(\d{1,2})(?:\s+at\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?)?$/i.exec(
|
|
10442
|
+
text
|
|
10443
|
+
);
|
|
10444
|
+
if (match == null) {
|
|
10445
|
+
return null;
|
|
10446
|
+
}
|
|
10447
|
+
const [, monthName, day, hour = "0", minute = "0", meridiem] = match;
|
|
10448
|
+
const month = parseMonth(monthName);
|
|
10449
|
+
if (month == null) {
|
|
10450
|
+
return null;
|
|
10451
|
+
}
|
|
10452
|
+
return buildFutureDate(now, sourceTimeZone, {
|
|
10453
|
+
month,
|
|
10454
|
+
day: Number(day),
|
|
10455
|
+
hour: parseHour(hour, meridiem),
|
|
10456
|
+
minute: Number(minute)
|
|
10457
|
+
});
|
|
10458
|
+
}
|
|
10459
|
+
function parseDayMonthAtTime(text, now, sourceTimeZone) {
|
|
10460
|
+
const match = /^(\d{1,2})\s+([A-Za-z]+)(?:\s+at\s+(\d{1,2})(?::(\d{2}))?\s*(am|pm)?)?$/i.exec(
|
|
10461
|
+
text
|
|
10462
|
+
);
|
|
10463
|
+
if (match == null) {
|
|
10464
|
+
return null;
|
|
10465
|
+
}
|
|
10466
|
+
const [, day, monthName, hour = "0", minute = "0", meridiem] = match;
|
|
10467
|
+
const month = parseMonth(monthName);
|
|
10468
|
+
if (month == null) {
|
|
10469
|
+
return null;
|
|
10470
|
+
}
|
|
10471
|
+
return buildFutureDate(now, sourceTimeZone, {
|
|
10472
|
+
month,
|
|
10473
|
+
day: Number(day),
|
|
10474
|
+
hour: parseHour(hour, meridiem),
|
|
10475
|
+
minute: Number(minute)
|
|
10476
|
+
});
|
|
10477
|
+
}
|
|
10478
|
+
function parseTimeOnly(text, now, sourceTimeZone) {
|
|
10479
|
+
const match = /^(\d{1,2})(?::(\d{2}))?\s*(am|pm)?$/i.exec(text);
|
|
10480
|
+
if (match == null) {
|
|
10481
|
+
return null;
|
|
10482
|
+
}
|
|
10483
|
+
const [, hour, minute = "0", meridiem] = match;
|
|
10484
|
+
const date = sourceTimeZone === "utc" ? new Date(
|
|
10485
|
+
Date.UTC(
|
|
10486
|
+
now.getUTCFullYear(),
|
|
10487
|
+
now.getUTCMonth(),
|
|
10488
|
+
now.getUTCDate(),
|
|
10489
|
+
parseHour(hour, meridiem),
|
|
10490
|
+
Number(minute)
|
|
10491
|
+
)
|
|
10492
|
+
) : new Date(
|
|
10493
|
+
now.getFullYear(),
|
|
10494
|
+
now.getMonth(),
|
|
10495
|
+
now.getDate(),
|
|
10496
|
+
parseHour(hour, meridiem),
|
|
10497
|
+
Number(minute)
|
|
10498
|
+
);
|
|
10499
|
+
if (date <= now) {
|
|
10500
|
+
if (sourceTimeZone === "utc") {
|
|
10501
|
+
date.setUTCDate(date.getUTCDate() + 1);
|
|
10502
|
+
} else {
|
|
10503
|
+
date.setDate(date.getDate() + 1);
|
|
10504
|
+
}
|
|
10505
|
+
}
|
|
10506
|
+
return date.toISOString();
|
|
10507
|
+
}
|
|
10508
|
+
function buildFutureDate(now, sourceTimeZone, values) {
|
|
10509
|
+
const date = sourceTimeZone === "utc" ? new Date(
|
|
10510
|
+
Date.UTC(now.getUTCFullYear(), values.month, values.day, values.hour, values.minute)
|
|
10511
|
+
) : new Date(now.getFullYear(), values.month, values.day, values.hour, values.minute);
|
|
10512
|
+
if (date <= now) {
|
|
10513
|
+
if (sourceTimeZone === "utc") {
|
|
10514
|
+
date.setUTCFullYear(date.getUTCFullYear() + 1);
|
|
10515
|
+
} else {
|
|
10516
|
+
date.setFullYear(date.getFullYear() + 1);
|
|
10517
|
+
}
|
|
10518
|
+
}
|
|
10519
|
+
return date.toISOString();
|
|
10520
|
+
}
|
|
10521
|
+
function normalizeResetText(resetText) {
|
|
10522
|
+
return (resetText ?? "").replace(/^resets\s+/i, "").replace(/\([^)]*\)/g, "").replace(/\s+/g, " ").trim();
|
|
10523
|
+
}
|
|
10524
|
+
function parseMonth(monthName) {
|
|
10525
|
+
return MONTHS.get(monthName.toLowerCase()) ?? null;
|
|
10526
|
+
}
|
|
10527
|
+
function parseHour(hourValue, meridiem) {
|
|
10528
|
+
const hour = Number(hourValue);
|
|
10529
|
+
if (meridiem == null) {
|
|
10530
|
+
return hour;
|
|
10531
|
+
}
|
|
10532
|
+
const lower = meridiem.toLowerCase();
|
|
10533
|
+
if (lower === "am") {
|
|
10534
|
+
return hour === 12 ? 0 : hour;
|
|
10535
|
+
}
|
|
10536
|
+
if (lower === "pm") {
|
|
10537
|
+
return hour === 12 ? 12 : hour + 12;
|
|
10538
|
+
}
|
|
10539
|
+
return hour;
|
|
10540
|
+
}
|
|
10541
|
+
function emptyToNull(value) {
|
|
10542
|
+
return value == null || value === "" ? null : value;
|
|
10543
|
+
}
|
|
10544
|
+
function escapeRegExp(value) {
|
|
10545
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10546
|
+
}
|
|
10547
|
+
const USAGE_BAR_WIDTH = 12;
|
|
10548
|
+
const ANSI = {
|
|
10549
|
+
reset: "\x1B[0m",
|
|
10550
|
+
bold: "\x1B[1m",
|
|
10551
|
+
dim: "\x1B[2m",
|
|
10552
|
+
green: "\x1B[32m",
|
|
10553
|
+
yellow: "\x1B[33m",
|
|
10554
|
+
orange: "\x1B[38;5;208m",
|
|
10555
|
+
red: "\x1B[31m",
|
|
10556
|
+
gray: "\x1B[90m"
|
|
10557
|
+
};
|
|
10558
|
+
const DEFAULT_USAGE_TIMEOUT_MS = 3e4;
|
|
10559
|
+
const MS_PER_MINUTE = 6e4;
|
|
10560
|
+
const MS_PER_HOUR = 36e5;
|
|
10561
|
+
const MS_PER_DAY = 864e5;
|
|
10562
|
+
const DETAILED_RESET_THRESHOLD_MINUTES = 180;
|
|
10563
|
+
const RELATIVE_RESET_WIDTH = 6;
|
|
10564
|
+
const RESET_WEEKDAY_TIME_FORMATTER = new Intl.DateTimeFormat("en-US", {
|
|
10565
|
+
weekday: "short",
|
|
10566
|
+
hour: "numeric",
|
|
10567
|
+
minute: "2-digit"
|
|
10568
|
+
});
|
|
10569
|
+
const RESET_DATE_TIME_FORMATTER = new Intl.DateTimeFormat("en-US", {
|
|
10570
|
+
month: "short",
|
|
10571
|
+
day: "numeric",
|
|
10572
|
+
hour: "numeric",
|
|
10573
|
+
minute: "2-digit"
|
|
10574
|
+
});
|
|
10575
|
+
class UsageExtractionTimeoutError extends Error {
|
|
10576
|
+
constructor(timeoutMs) {
|
|
10577
|
+
super(`Usage extraction timed out after ${formatDuration(timeoutMs)}.`);
|
|
10578
|
+
this.timeoutMs = timeoutMs;
|
|
10579
|
+
}
|
|
10580
|
+
}
|
|
10581
|
+
function normalizeOptionalWindow(value) {
|
|
10582
|
+
if (value == null) {
|
|
10583
|
+
return null;
|
|
10584
|
+
}
|
|
10585
|
+
const trimmed = value.trim();
|
|
10586
|
+
return trimmed.length > 0 ? normalizeUsageWindow(trimmed) : "";
|
|
10587
|
+
}
|
|
10588
|
+
function normalizeOptionalSort(value) {
|
|
10589
|
+
if (value == null) {
|
|
10590
|
+
return null;
|
|
10591
|
+
}
|
|
10592
|
+
const normalized = value.trim().toLowerCase();
|
|
10593
|
+
if (!normalized) {
|
|
10594
|
+
return "";
|
|
10595
|
+
}
|
|
10596
|
+
return normalized === "reset" || normalized === "left" ? normalized : "";
|
|
10597
|
+
}
|
|
10598
|
+
function parseTimeoutMs(value) {
|
|
10599
|
+
if (value == null) {
|
|
10600
|
+
return void 0;
|
|
10601
|
+
}
|
|
10602
|
+
const trimmed = value.trim();
|
|
10603
|
+
if (!trimmed) {
|
|
10604
|
+
return null;
|
|
10605
|
+
}
|
|
10606
|
+
const match = /^(\d+(?:\.\d+)?)(ms|s|m)?$/i.exec(trimmed);
|
|
10607
|
+
if (!match) {
|
|
10608
|
+
return null;
|
|
10609
|
+
}
|
|
10610
|
+
const amount = Number(match[1]);
|
|
10611
|
+
const unit = match[2]?.toLowerCase() ?? "s";
|
|
10612
|
+
const multiplier = unit === "ms" ? 1 : unit === "m" ? 6e4 : 1e3;
|
|
10613
|
+
const timeoutMs = amount * multiplier;
|
|
10614
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
|
|
10615
|
+
return null;
|
|
10616
|
+
}
|
|
10617
|
+
return Math.ceil(timeoutMs);
|
|
10618
|
+
}
|
|
10619
|
+
function resolveTargetTimeoutMs(target, cliTimeoutMs) {
|
|
10620
|
+
return cliTimeoutMs ?? target.usage?.launch?.timeoutMs ?? DEFAULT_USAGE_TIMEOUT_MS;
|
|
10621
|
+
}
|
|
10622
|
+
function parseList(value) {
|
|
10623
|
+
if (!value) {
|
|
10624
|
+
return [];
|
|
10625
|
+
}
|
|
10626
|
+
const rawValues = Array.isArray(value) ? value : [value];
|
|
10627
|
+
return rawValues.flatMap((entry2) => entry2.split(",")).map((entry2) => entry2.trim().toLowerCase()).filter(Boolean);
|
|
10628
|
+
}
|
|
10629
|
+
function formatDuration(timeoutMs) {
|
|
10630
|
+
if (timeoutMs % 6e4 === 0) {
|
|
10631
|
+
return `${timeoutMs / 6e4}m`;
|
|
10632
|
+
}
|
|
10633
|
+
if (timeoutMs % 1e3 === 0) {
|
|
10634
|
+
return `${timeoutMs / 1e3}s`;
|
|
10635
|
+
}
|
|
10636
|
+
return `${timeoutMs}ms`;
|
|
10637
|
+
}
|
|
10638
|
+
function uniqueNormalizedWindows(values) {
|
|
10639
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10640
|
+
const result = [];
|
|
10641
|
+
for (const value of values) {
|
|
10642
|
+
const normalized = normalizeUsageWindow(value);
|
|
10643
|
+
if (!normalized || seen.has(normalized)) {
|
|
10644
|
+
continue;
|
|
10645
|
+
}
|
|
10646
|
+
seen.add(normalized);
|
|
10647
|
+
result.push(normalized);
|
|
10648
|
+
}
|
|
10649
|
+
return result;
|
|
10650
|
+
}
|
|
10651
|
+
function formatUsageTargetLabel(targets) {
|
|
10652
|
+
return buildSupportedTargetLabel(targets);
|
|
10653
|
+
}
|
|
10654
|
+
function formatSupportedUsageTargetsMessage(targets) {
|
|
10655
|
+
const supportedUsageTargets = formatUsageTargetLabel(targets);
|
|
10656
|
+
return supportedUsageTargets ? `Supported usage targets: ${supportedUsageTargets}.` : "No active usage-capable targets are enabled by the current target configuration.";
|
|
10657
|
+
}
|
|
10658
|
+
function getUsageCommand(target) {
|
|
10659
|
+
return target.usage?.launch?.command;
|
|
10660
|
+
}
|
|
10661
|
+
async function checkUsageCommandAvailability(target) {
|
|
10662
|
+
const command = getUsageCommand(target)?.trim();
|
|
10663
|
+
if (!command) {
|
|
10664
|
+
return {
|
|
10665
|
+
status: "available",
|
|
10666
|
+
warnings: []
|
|
10667
|
+
};
|
|
10668
|
+
}
|
|
10669
|
+
const check = await checkCliOnPath(command);
|
|
10670
|
+
if (check.result === "available") {
|
|
10671
|
+
return {
|
|
10672
|
+
status: "available",
|
|
10673
|
+
warnings: [],
|
|
10674
|
+
command,
|
|
10675
|
+
resolvedPath: check.resolvedPath ?? command
|
|
10676
|
+
};
|
|
10677
|
+
}
|
|
10678
|
+
if (check.result === "inconclusive") {
|
|
10679
|
+
return {
|
|
10680
|
+
status: "unavailable",
|
|
10681
|
+
reason: "Usage CLI availability could not be confirmed.",
|
|
10682
|
+
warnings: check.warning ? [check.warning] : []
|
|
10683
|
+
};
|
|
10684
|
+
}
|
|
10685
|
+
return {
|
|
10686
|
+
status: "unavailable",
|
|
10687
|
+
reason: `Usage CLI not found on PATH: ${command}.`,
|
|
10688
|
+
warnings: []
|
|
10689
|
+
};
|
|
10690
|
+
}
|
|
10691
|
+
function buildContext(options) {
|
|
10692
|
+
const windows = uniqueNormalizedWindows(options.target.usage?.windows ?? []);
|
|
10693
|
+
const launch = {
|
|
10694
|
+
...options.target.usage?.launch ?? {},
|
|
10695
|
+
timeoutMs: options.timeoutMs
|
|
10696
|
+
};
|
|
10697
|
+
return {
|
|
10698
|
+
targetId: options.target.id,
|
|
10699
|
+
displayName: options.target.displayName,
|
|
10700
|
+
command: options.command ?? getUsageCommand(options.target),
|
|
10701
|
+
window: options.selectedWindow ?? windows[0] ?? "",
|
|
10702
|
+
windows,
|
|
10703
|
+
now: options.now,
|
|
10704
|
+
repoRoot: options.repoRoot,
|
|
10705
|
+
agentsDir: options.agentsDir,
|
|
10706
|
+
homeDir: options.homeDir,
|
|
10707
|
+
launch,
|
|
10708
|
+
signal: options.signal,
|
|
10709
|
+
debug: {
|
|
10710
|
+
enabled: options.debug,
|
|
10711
|
+
includeRawOutput: options.debug,
|
|
10712
|
+
includeScreenSnapshots: options.debug
|
|
10713
|
+
}
|
|
10714
|
+
};
|
|
10715
|
+
}
|
|
10716
|
+
function filterTargetResult(target, result, selectedWindow) {
|
|
10717
|
+
const normalizedLimits = result.limits.map((limit) => ({
|
|
10718
|
+
...limit,
|
|
10719
|
+
window: normalizeUsageWindow(limit.window)
|
|
10720
|
+
}));
|
|
10721
|
+
const filteredLimits = selectedWindow == null ? normalizedLimits : normalizedLimits.filter((limit) => limit.window === selectedWindow);
|
|
10722
|
+
const notes = selectedWindow != null && filteredLimits.length === 0 ? [`${target.displayName} reported no usage rows for window "${selectedWindow}".`] : [];
|
|
10723
|
+
return {
|
|
10724
|
+
result: {
|
|
10725
|
+
targetId: result.targetId,
|
|
10726
|
+
displayName: result.displayName,
|
|
10727
|
+
command: result.command,
|
|
10728
|
+
limits: filteredLimits
|
|
10729
|
+
},
|
|
10730
|
+
notes,
|
|
10731
|
+
debug: result.debug ?? []
|
|
10732
|
+
};
|
|
10733
|
+
}
|
|
10734
|
+
function buildError(target, code, message) {
|
|
10735
|
+
return {
|
|
10736
|
+
targetId: target.id,
|
|
10737
|
+
displayName: target.displayName,
|
|
10738
|
+
code,
|
|
10739
|
+
message
|
|
10740
|
+
};
|
|
10741
|
+
}
|
|
10742
|
+
async function extractUsageForTarget(options) {
|
|
10743
|
+
try {
|
|
10744
|
+
const extractor = options.target.usage?.extract;
|
|
10745
|
+
if (!extractor) {
|
|
10746
|
+
return {
|
|
10747
|
+
status: "error",
|
|
10748
|
+
target: options.target,
|
|
10749
|
+
error: buildError(
|
|
10750
|
+
options.target,
|
|
10751
|
+
"usage_extractor_missing",
|
|
10752
|
+
`${options.target.displayName} does not have a usage extractor.`
|
|
10753
|
+
),
|
|
10754
|
+
debug: []
|
|
10755
|
+
};
|
|
10756
|
+
}
|
|
10757
|
+
const result = await withUsageTimeout((signal) => {
|
|
10758
|
+
const context = buildContext({ ...options, signal });
|
|
10759
|
+
return extractor(context);
|
|
10760
|
+
}, options.timeoutMs);
|
|
10761
|
+
const filtered = filterTargetResult(options.target, result, options.selectedWindow);
|
|
10762
|
+
return {
|
|
10763
|
+
status: "success",
|
|
10764
|
+
target: options.target,
|
|
10765
|
+
result: filtered.result,
|
|
10766
|
+
errors: result.errors ?? [],
|
|
10767
|
+
notes: filtered.notes,
|
|
10768
|
+
debug: filtered.debug
|
|
10769
|
+
};
|
|
10770
|
+
} catch (error) {
|
|
10771
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
10772
|
+
const code = isUsageTimeoutError(error) ? "usage_extraction_timeout" : "usage_extraction_failed";
|
|
10773
|
+
return {
|
|
10774
|
+
status: "error",
|
|
10775
|
+
target: options.target,
|
|
10776
|
+
error: buildError(options.target, code, message),
|
|
10777
|
+
debug: options.debug ? getErrorDebugArtifacts(error) : []
|
|
10778
|
+
};
|
|
10779
|
+
}
|
|
10780
|
+
}
|
|
10781
|
+
function isUsageTimeoutError(error) {
|
|
10782
|
+
if (error instanceof UsageExtractionTimeoutError) {
|
|
10783
|
+
return true;
|
|
10784
|
+
}
|
|
10785
|
+
return Boolean(error && typeof error === "object" && error.timedOut);
|
|
10786
|
+
}
|
|
10787
|
+
function getErrorDebugArtifacts(error) {
|
|
10788
|
+
if (!error || typeof error !== "object") {
|
|
10789
|
+
return [];
|
|
10790
|
+
}
|
|
10791
|
+
const debug = error.debug;
|
|
10792
|
+
if (!Array.isArray(debug)) {
|
|
10793
|
+
return [];
|
|
10794
|
+
}
|
|
10795
|
+
return debug.filter(isDebugArtifact);
|
|
10796
|
+
}
|
|
10797
|
+
function isDebugArtifact(value) {
|
|
10798
|
+
if (!value || typeof value !== "object") {
|
|
10799
|
+
return false;
|
|
10800
|
+
}
|
|
10801
|
+
const artifact = value;
|
|
10802
|
+
return (artifact.type === "raw-output" || artifact.type === "screen-snapshot") && typeof artifact.label === "string";
|
|
10803
|
+
}
|
|
10804
|
+
function withUsageTimeout(run, timeoutMs) {
|
|
10805
|
+
return new Promise((resolve, reject) => {
|
|
10806
|
+
const controller = new AbortController();
|
|
10807
|
+
let settled = false;
|
|
10808
|
+
let timeoutFired = false;
|
|
10809
|
+
let timeout;
|
|
10810
|
+
const settleResolve = (value) => {
|
|
10811
|
+
if (settled) {
|
|
10812
|
+
return;
|
|
10813
|
+
}
|
|
10814
|
+
settled = true;
|
|
10815
|
+
clearTimeout(timeout);
|
|
10816
|
+
resolve(value);
|
|
10817
|
+
};
|
|
10818
|
+
const settleReject = (error) => {
|
|
10819
|
+
if (settled) {
|
|
10820
|
+
return;
|
|
10821
|
+
}
|
|
10822
|
+
settled = true;
|
|
10823
|
+
clearTimeout(timeout);
|
|
10824
|
+
reject(error);
|
|
10825
|
+
};
|
|
10826
|
+
timeout = setTimeout(() => {
|
|
10827
|
+
timeoutFired = true;
|
|
10828
|
+
const error = new UsageExtractionTimeoutError(timeoutMs);
|
|
10829
|
+
controller.abort(error);
|
|
10830
|
+
setImmediate(() => {
|
|
10831
|
+
settleReject(error);
|
|
10832
|
+
});
|
|
10833
|
+
}, timeoutMs);
|
|
10834
|
+
let promise;
|
|
10835
|
+
try {
|
|
10836
|
+
promise = run(controller.signal);
|
|
10837
|
+
} catch (error) {
|
|
10838
|
+
settleReject(error);
|
|
10839
|
+
return;
|
|
10840
|
+
}
|
|
10841
|
+
promise.then(
|
|
10842
|
+
(value) => {
|
|
10843
|
+
if (timeoutFired) {
|
|
10844
|
+
return;
|
|
10845
|
+
}
|
|
10846
|
+
settleResolve(value);
|
|
10847
|
+
},
|
|
10848
|
+
(error) => {
|
|
10849
|
+
if (timeoutFired && !isUsageTimeoutError(error)) {
|
|
10850
|
+
return;
|
|
10851
|
+
}
|
|
10852
|
+
settleReject(error);
|
|
10853
|
+
}
|
|
10854
|
+
);
|
|
10855
|
+
});
|
|
10856
|
+
}
|
|
10857
|
+
function buildEnvelope(options) {
|
|
10858
|
+
const envelope = {
|
|
10859
|
+
schemaVersion: 1,
|
|
10860
|
+
generatedAt: options.generatedAt,
|
|
10861
|
+
targets: options.targets,
|
|
10862
|
+
errors: options.errors,
|
|
10863
|
+
notes: options.notes
|
|
10864
|
+
};
|
|
10865
|
+
if (options.debug && options.debugArtifacts.length > 0) {
|
|
10866
|
+
envelope.debug = options.debugArtifacts;
|
|
10867
|
+
}
|
|
10868
|
+
return envelope;
|
|
10869
|
+
}
|
|
10870
|
+
function buildCommandError(code, message) {
|
|
10871
|
+
return {
|
|
10872
|
+
targetId: "usage",
|
|
10873
|
+
displayName: "Usage command",
|
|
10874
|
+
code,
|
|
10875
|
+
message
|
|
10876
|
+
};
|
|
10877
|
+
}
|
|
10878
|
+
function printError(options) {
|
|
10879
|
+
if (options.json) {
|
|
10880
|
+
const error = options.target ? buildError(options.target, options.code, options.message) : buildCommandError(options.code, options.message);
|
|
10881
|
+
console.log(
|
|
10882
|
+
JSON.stringify(
|
|
10883
|
+
buildEnvelope({
|
|
10884
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10885
|
+
targets: [],
|
|
10886
|
+
errors: [error],
|
|
10887
|
+
notes: [],
|
|
10888
|
+
debug: false,
|
|
10889
|
+
debugArtifacts: []
|
|
10890
|
+
}),
|
|
10891
|
+
null,
|
|
10892
|
+
2
|
|
10893
|
+
)
|
|
10894
|
+
);
|
|
10895
|
+
} else {
|
|
10896
|
+
console.error(`Error: ${options.message}`);
|
|
10897
|
+
}
|
|
10898
|
+
process.exit(options.exitCode);
|
|
10899
|
+
}
|
|
10900
|
+
function percentText(value) {
|
|
10901
|
+
return value == null ? "unknown" : `${Math.round(value)}%`;
|
|
10902
|
+
}
|
|
10903
|
+
function usageBar(percentUsed) {
|
|
10904
|
+
if (percentUsed == null) {
|
|
10905
|
+
return `[${"?".repeat(USAGE_BAR_WIDTH)}]`;
|
|
10906
|
+
}
|
|
10907
|
+
const clamped = Math.max(0, Math.min(100, percentUsed));
|
|
10908
|
+
const filled = clamped === 0 ? 0 : Math.max(1, Math.round(clamped / 100 * USAGE_BAR_WIDTH));
|
|
10909
|
+
return `[${"#".repeat(filled)}${"-".repeat(USAGE_BAR_WIDTH - filled)}]`;
|
|
10910
|
+
}
|
|
10911
|
+
function formatResetValue(limit, now) {
|
|
10912
|
+
const resetAt = parseDate(limit.resetAt);
|
|
10913
|
+
if (resetAt != null) {
|
|
10914
|
+
return formatLocalResetAt(resetAt, now);
|
|
10915
|
+
}
|
|
10916
|
+
const value = limit.resetText ?? "-";
|
|
10917
|
+
return value === "-" ? value : value.replace(/^resets\s+/i, "");
|
|
10918
|
+
}
|
|
10919
|
+
function parseDate(value) {
|
|
10920
|
+
if (!value) {
|
|
10921
|
+
return null;
|
|
10922
|
+
}
|
|
10923
|
+
const date = new Date(value);
|
|
10924
|
+
return Number.isNaN(date.getTime()) ? null : date;
|
|
10925
|
+
}
|
|
10926
|
+
function formatLocalResetAt(resetAt, now) {
|
|
10927
|
+
const relative = formatResetDuration(resetAt.getTime() - now.getTime()).padEnd(
|
|
10928
|
+
RELATIVE_RESET_WIDTH
|
|
10929
|
+
);
|
|
10930
|
+
return `${relative} (${formatResetExact(resetAt, now)})`;
|
|
10931
|
+
}
|
|
10932
|
+
function formatResetDuration(milliseconds) {
|
|
10933
|
+
if (milliseconds <= 0) {
|
|
10934
|
+
return "now";
|
|
10935
|
+
}
|
|
10936
|
+
const totalMinutes = Math.max(1, Math.ceil(milliseconds / MS_PER_MINUTE));
|
|
10937
|
+
if (totalMinutes < 60) {
|
|
10938
|
+
return `${totalMinutes}m`;
|
|
10939
|
+
}
|
|
10940
|
+
if (totalMinutes < DETAILED_RESET_THRESHOLD_MINUTES) {
|
|
10941
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
10942
|
+
const minutes = totalMinutes % 60;
|
|
10943
|
+
return minutes === 0 ? `${hours}h` : `${hours}h${minutes}m`;
|
|
10944
|
+
}
|
|
10945
|
+
if (milliseconds >= MS_PER_DAY) {
|
|
10946
|
+
return `${Math.ceil(milliseconds / MS_PER_DAY)}d`;
|
|
10947
|
+
}
|
|
10948
|
+
return `${Math.round(milliseconds / MS_PER_HOUR)}h`;
|
|
10949
|
+
}
|
|
10950
|
+
function formatResetExact(resetAt, now) {
|
|
10951
|
+
const dayDifference = localDayIndex(resetAt) - localDayIndex(now);
|
|
10952
|
+
if (dayDifference >= 0 && dayDifference <= 7) {
|
|
10953
|
+
return RESET_WEEKDAY_TIME_FORMATTER.format(resetAt);
|
|
10954
|
+
}
|
|
10955
|
+
return RESET_DATE_TIME_FORMATTER.format(resetAt);
|
|
10956
|
+
}
|
|
10957
|
+
function localDayIndex(date) {
|
|
10958
|
+
return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) / MS_PER_DAY;
|
|
10959
|
+
}
|
|
10960
|
+
function formatLimitLabel(limit) {
|
|
10961
|
+
return limit.label ?? limit.modelLabel ?? limit.modelId ?? formatWindowLabel(limit.window);
|
|
10962
|
+
}
|
|
10963
|
+
function formatLimitLabels(limits) {
|
|
10964
|
+
const baseLabels = limits.map(formatLimitLabel);
|
|
10965
|
+
const duplicateLabels = new Set(
|
|
10966
|
+
baseLabels.filter((label, index) => baseLabels.indexOf(label) !== index)
|
|
10967
|
+
);
|
|
10968
|
+
return limits.map((limit, index) => {
|
|
10969
|
+
const baseLabel = baseLabels[index] ?? formatLimitLabel(limit);
|
|
10970
|
+
if (!duplicateLabels.has(baseLabel) || !limit.scope) {
|
|
10971
|
+
return baseLabel;
|
|
10972
|
+
}
|
|
10973
|
+
if (limit.scope === "main") {
|
|
10974
|
+
return baseLabel;
|
|
10975
|
+
}
|
|
10976
|
+
return `${formatScopeLabel(limit.scope)} ${baseLabel}`;
|
|
10977
|
+
});
|
|
10978
|
+
}
|
|
10979
|
+
function formatScopeLabel(scope) {
|
|
10980
|
+
return scope.replace(/[_-]+/g, " ").split(/\s+/).filter(Boolean).map((word) => `${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(" ");
|
|
10981
|
+
}
|
|
10982
|
+
function formatWindowLabel(window) {
|
|
10983
|
+
if (window === "hourly") {
|
|
10984
|
+
return "5h";
|
|
10985
|
+
}
|
|
10986
|
+
if (window === "weekly") {
|
|
10987
|
+
return "Weekly";
|
|
10988
|
+
}
|
|
10989
|
+
return window;
|
|
10990
|
+
}
|
|
10991
|
+
function formatUsageTable(envelope, sortKey) {
|
|
10992
|
+
const useColor = shouldUseColor();
|
|
10993
|
+
const generatedAt = parseDate(envelope.generatedAt) ?? /* @__PURE__ */ new Date();
|
|
10994
|
+
const rows = [];
|
|
10995
|
+
for (const target of envelope.targets) {
|
|
10996
|
+
const limitLabels = formatLimitLabels(target.limits);
|
|
10997
|
+
target.limits.forEach((limit, index) => {
|
|
10998
|
+
rows.push({
|
|
10999
|
+
status: "ok",
|
|
11000
|
+
agent: sortKey == null && index > 0 ? "" : target.displayName,
|
|
11001
|
+
limitLabel: limitLabels[index] ?? formatLimitLabel(limit),
|
|
11002
|
+
reset: formatResetValue(limit, generatedAt),
|
|
11003
|
+
limit
|
|
11004
|
+
});
|
|
11005
|
+
});
|
|
11006
|
+
}
|
|
11007
|
+
for (const error of envelope.errors) {
|
|
11008
|
+
rows.push({
|
|
11009
|
+
status: "error",
|
|
11010
|
+
agent: error.displayName,
|
|
11011
|
+
limitLabel: "error",
|
|
11012
|
+
message: error.message
|
|
11013
|
+
});
|
|
11014
|
+
}
|
|
11015
|
+
const rendered = [renderUsageTable(sortUsageRows(rows, sortKey), useColor)];
|
|
11016
|
+
if (envelope.notes.length > 0) {
|
|
11017
|
+
rendered.push("", ...envelope.notes.map((note) => color(`Note: ${note}`, "dim", useColor)));
|
|
11018
|
+
}
|
|
11019
|
+
return rendered.join("\n");
|
|
11020
|
+
}
|
|
11021
|
+
function sortUsageRows(rows, sortKey) {
|
|
11022
|
+
if (sortKey == null) {
|
|
11023
|
+
return rows;
|
|
11024
|
+
}
|
|
11025
|
+
return rows.map((row, index) => ({ row, index })).sort((left, right) => {
|
|
11026
|
+
const leftValue = usageSortValue(left.row, sortKey);
|
|
11027
|
+
const rightValue = usageSortValue(right.row, sortKey);
|
|
11028
|
+
if (leftValue == null && rightValue == null) {
|
|
11029
|
+
return left.index - right.index;
|
|
11030
|
+
}
|
|
11031
|
+
if (leftValue == null) {
|
|
11032
|
+
return 1;
|
|
11033
|
+
}
|
|
11034
|
+
if (rightValue == null) {
|
|
11035
|
+
return -1;
|
|
11036
|
+
}
|
|
11037
|
+
if (leftValue !== rightValue) {
|
|
11038
|
+
return leftValue - rightValue;
|
|
11039
|
+
}
|
|
11040
|
+
return left.index - right.index;
|
|
11041
|
+
}).map(({ row }) => row);
|
|
11042
|
+
}
|
|
11043
|
+
function usageSortValue(row, sortKey) {
|
|
11044
|
+
if (row.status === "error") {
|
|
11045
|
+
return null;
|
|
11046
|
+
}
|
|
11047
|
+
if (sortKey === "left") {
|
|
11048
|
+
return row.limit.percentRemaining;
|
|
11049
|
+
}
|
|
11050
|
+
const resetAt = parseDate(row.limit.resetAt);
|
|
11051
|
+
return resetAt?.getTime() ?? null;
|
|
11052
|
+
}
|
|
11053
|
+
function renderUsageTable(rows, useColor) {
|
|
11054
|
+
const widths = {
|
|
11055
|
+
agent: maxWidth(
|
|
11056
|
+
"Agent",
|
|
11057
|
+
rows.map((row) => row.agent)
|
|
11058
|
+
),
|
|
11059
|
+
limit: maxWidth(
|
|
11060
|
+
"Limit",
|
|
11061
|
+
rows.map((row) => row.limitLabel)
|
|
11062
|
+
),
|
|
11063
|
+
usage: maxWidth("Usage", rows.map(usageCellText)),
|
|
11064
|
+
left: maxWidth("Left", rows.map(leftCellText)),
|
|
11065
|
+
reset: maxWidth("Reset", rows.map(resetCellText))
|
|
11066
|
+
};
|
|
11067
|
+
const headerLine = [
|
|
11068
|
+
pad("Agent", widths.agent),
|
|
11069
|
+
pad("Limit", widths.limit),
|
|
11070
|
+
pad("Left", widths.left),
|
|
11071
|
+
pad("Usage", widths.usage),
|
|
11072
|
+
pad("Reset", widths.reset)
|
|
11073
|
+
].join(" ").trimEnd();
|
|
11074
|
+
const separatorLine = [
|
|
11075
|
+
"-".repeat(widths.agent),
|
|
11076
|
+
"-".repeat(widths.limit),
|
|
11077
|
+
"-".repeat(widths.left),
|
|
11078
|
+
"-".repeat(widths.usage),
|
|
11079
|
+
"-".repeat(widths.reset)
|
|
11080
|
+
].join(" ").trimEnd();
|
|
11081
|
+
return [
|
|
11082
|
+
color(headerLine, "bold", useColor),
|
|
11083
|
+
color(separatorLine, "dim", useColor),
|
|
11084
|
+
...rows.map((row) => renderUsageRow(row, widths, useColor))
|
|
11085
|
+
].join("\n");
|
|
11086
|
+
}
|
|
11087
|
+
function renderUsageRow(row, widths, useColor) {
|
|
11088
|
+
return [
|
|
11089
|
+
pad(row.agent, widths.agent),
|
|
11090
|
+
pad(row.limitLabel, widths.limit),
|
|
11091
|
+
renderLeftCell(row, widths.left, useColor),
|
|
11092
|
+
renderUsageCell(row, widths.usage, useColor),
|
|
11093
|
+
renderResetCell(row, widths.reset, useColor)
|
|
11094
|
+
].join(" ").trimEnd();
|
|
11095
|
+
}
|
|
11096
|
+
function usageCellText(row) {
|
|
11097
|
+
if (row.status === "error") {
|
|
11098
|
+
return "failed";
|
|
11099
|
+
}
|
|
11100
|
+
return `${usageBar(row.limit.percentUsed)} ${percentText(row.limit.percentUsed).padStart(4)} used`;
|
|
11101
|
+
}
|
|
11102
|
+
function leftCellText(row) {
|
|
11103
|
+
if (row.status === "error") {
|
|
11104
|
+
return "-";
|
|
11105
|
+
}
|
|
11106
|
+
return percentText(row.limit.percentRemaining);
|
|
11107
|
+
}
|
|
11108
|
+
function resetCellText(row) {
|
|
11109
|
+
if (row.status === "error") {
|
|
11110
|
+
return `Error: ${row.message}`;
|
|
11111
|
+
}
|
|
11112
|
+
return row.reset;
|
|
11113
|
+
}
|
|
11114
|
+
function renderUsageCell(row, width, useColor) {
|
|
11115
|
+
const text = usageCellText(row);
|
|
11116
|
+
const padding = " ".repeat(Math.max(0, width - text.length));
|
|
11117
|
+
if (row.status === "error") {
|
|
11118
|
+
return `${color(text, "red", useColor)}${padding}`;
|
|
11119
|
+
}
|
|
11120
|
+
const severity = usageSeverity(row.limit.percentUsed);
|
|
11121
|
+
const used = percentText(row.limit.percentUsed).padStart(4);
|
|
11122
|
+
return `${color(usageBar(row.limit.percentUsed), severity, useColor)} ${color(
|
|
11123
|
+
used,
|
|
11124
|
+
severity,
|
|
11125
|
+
useColor
|
|
11126
|
+
)} used${padding}`;
|
|
11127
|
+
}
|
|
11128
|
+
function renderLeftCell(row, width, useColor) {
|
|
11129
|
+
const text = leftCellText(row);
|
|
11130
|
+
const padding = " ".repeat(Math.max(0, width - text.length));
|
|
11131
|
+
if (row.status === "error") {
|
|
11132
|
+
return `${color(text, "gray", useColor)}${padding}`;
|
|
11133
|
+
}
|
|
11134
|
+
return `${color(text, remainingSeverity(row.limit.percentRemaining), useColor)}${padding}`;
|
|
11135
|
+
}
|
|
11136
|
+
function renderResetCell(row, width, useColor) {
|
|
11137
|
+
const text = resetCellText(row);
|
|
11138
|
+
const padding = " ".repeat(Math.max(0, width - text.length));
|
|
11139
|
+
const style = row.status === "error" ? "red" : "gray";
|
|
11140
|
+
return `${color(text, style, useColor)}${padding}`;
|
|
11141
|
+
}
|
|
11142
|
+
function usageSeverity(percentUsed) {
|
|
11143
|
+
if (percentUsed == null) {
|
|
11144
|
+
return "gray";
|
|
11145
|
+
}
|
|
11146
|
+
if (percentUsed >= 95) {
|
|
11147
|
+
return "red";
|
|
11148
|
+
}
|
|
11149
|
+
if (percentUsed >= 80) {
|
|
11150
|
+
return "orange";
|
|
11151
|
+
}
|
|
11152
|
+
if (percentUsed >= 60) {
|
|
11153
|
+
return "yellow";
|
|
11154
|
+
}
|
|
11155
|
+
return "green";
|
|
11156
|
+
}
|
|
11157
|
+
function remainingSeverity(percentRemaining) {
|
|
11158
|
+
if (percentRemaining == null) {
|
|
11159
|
+
return "gray";
|
|
11160
|
+
}
|
|
11161
|
+
if (percentRemaining <= 5) {
|
|
11162
|
+
return "red";
|
|
11163
|
+
}
|
|
11164
|
+
if (percentRemaining <= 20) {
|
|
11165
|
+
return "orange";
|
|
11166
|
+
}
|
|
11167
|
+
if (percentRemaining <= 40) {
|
|
11168
|
+
return "yellow";
|
|
11169
|
+
}
|
|
11170
|
+
return "green";
|
|
11171
|
+
}
|
|
11172
|
+
function maxWidth(header, values) {
|
|
11173
|
+
return Math.max(header.length, ...values.map((value) => value.length));
|
|
11174
|
+
}
|
|
11175
|
+
function pad(value, width) {
|
|
11176
|
+
return value.padEnd(width);
|
|
11177
|
+
}
|
|
11178
|
+
function color(value, style, useColor) {
|
|
11179
|
+
if (!useColor) {
|
|
11180
|
+
return value;
|
|
11181
|
+
}
|
|
11182
|
+
return `${ANSI[style]}${value}${ANSI.reset}`;
|
|
11183
|
+
}
|
|
11184
|
+
function shouldUseColor() {
|
|
11185
|
+
if (process.env.FORCE_COLOR != null && process.env.FORCE_COLOR !== "0") {
|
|
11186
|
+
return true;
|
|
11187
|
+
}
|
|
11188
|
+
if (process.env.NO_COLOR != null) {
|
|
11189
|
+
return false;
|
|
11190
|
+
}
|
|
11191
|
+
return Boolean(process.stdout.isTTY);
|
|
11192
|
+
}
|
|
11193
|
+
async function runUsageCommand(argv) {
|
|
11194
|
+
const positionalTargets = argv.targets ?? [];
|
|
11195
|
+
const onlyTargets = parseList(argv.only);
|
|
11196
|
+
const jsonOutput = Boolean(argv.json || argv.debug);
|
|
11197
|
+
const debugOutput = Boolean(argv.debug);
|
|
11198
|
+
const selectedWindow = normalizeOptionalWindow(argv.window);
|
|
11199
|
+
const sortKey = normalizeOptionalSort(argv.sort);
|
|
11200
|
+
const cliTimeoutMs = parseTimeoutMs(argv.timeout);
|
|
11201
|
+
if (selectedWindow === "") {
|
|
11202
|
+
printError({
|
|
11203
|
+
json: jsonOutput,
|
|
11204
|
+
code: "invalid_window",
|
|
11205
|
+
message: "--window must be a non-empty value.",
|
|
11206
|
+
exitCode: 2
|
|
11207
|
+
});
|
|
11208
|
+
return null;
|
|
11209
|
+
}
|
|
11210
|
+
if (sortKey === "") {
|
|
11211
|
+
printError({
|
|
11212
|
+
json: jsonOutput,
|
|
11213
|
+
code: "invalid_sort",
|
|
11214
|
+
message: "--sort must be one of: reset, left.",
|
|
11215
|
+
exitCode: 2
|
|
11216
|
+
});
|
|
11217
|
+
return null;
|
|
11218
|
+
}
|
|
11219
|
+
if (sortKey != null && jsonOutput) {
|
|
11220
|
+
printError({
|
|
11221
|
+
json: jsonOutput,
|
|
11222
|
+
code: "sort_json_unsupported",
|
|
11223
|
+
message: "--sort is only supported for the human table output.",
|
|
11224
|
+
exitCode: 2
|
|
11225
|
+
});
|
|
11226
|
+
return null;
|
|
11227
|
+
}
|
|
11228
|
+
if (cliTimeoutMs === null) {
|
|
11229
|
+
printError({
|
|
11230
|
+
json: jsonOutput,
|
|
11231
|
+
code: "invalid_timeout",
|
|
11232
|
+
message: "--timeout must be a positive duration. Use seconds by default, or units like 500ms, 5s, or 1m.",
|
|
11233
|
+
exitCode: 2
|
|
11234
|
+
});
|
|
11235
|
+
return null;
|
|
11236
|
+
}
|
|
11237
|
+
if (argv.only != null && onlyTargets.length === 0) {
|
|
11238
|
+
printError({
|
|
11239
|
+
json: jsonOutput,
|
|
11240
|
+
code: "invalid_only",
|
|
11241
|
+
message: "--only must include at least one target.",
|
|
11242
|
+
exitCode: 2
|
|
11243
|
+
});
|
|
11244
|
+
return null;
|
|
11245
|
+
}
|
|
11246
|
+
if (positionalTargets.length > 1) {
|
|
11247
|
+
printError({
|
|
11248
|
+
json: jsonOutput,
|
|
11249
|
+
code: "too_many_targets",
|
|
11250
|
+
message: "omniagent usage accepts at most one target.",
|
|
11251
|
+
exitCode: 2
|
|
11252
|
+
});
|
|
11253
|
+
return null;
|
|
11254
|
+
}
|
|
11255
|
+
if (positionalTargets.length > 0 && onlyTargets.length > 0) {
|
|
11256
|
+
printError({
|
|
11257
|
+
json: jsonOutput,
|
|
11258
|
+
code: "conflicting_target_selection",
|
|
11259
|
+
message: "Use either a positional target or --only, not both.",
|
|
11260
|
+
exitCode: 2
|
|
11261
|
+
});
|
|
11262
|
+
return null;
|
|
11263
|
+
}
|
|
11264
|
+
const startDir = process.cwd();
|
|
11265
|
+
const repoRoot = await findRepoRoot(startDir);
|
|
11266
|
+
if (!repoRoot) {
|
|
11267
|
+
printError({
|
|
11268
|
+
json: jsonOutput,
|
|
11269
|
+
code: "repo_not_found",
|
|
11270
|
+
message: `Repository root not found starting from ${startDir}. Looked for .git or package.json.`,
|
|
11271
|
+
exitCode: 1
|
|
11272
|
+
});
|
|
11273
|
+
return null;
|
|
11274
|
+
}
|
|
11275
|
+
const agentsDirResolution = resolveAgentsDir(repoRoot, argv.agentsDir);
|
|
11276
|
+
if (agentsDirResolution.source === "override") {
|
|
11277
|
+
const validation2 = await validateAgentsDir(repoRoot, argv.agentsDir, { requireWrite: false });
|
|
11278
|
+
if (validation2.validationStatus !== "valid") {
|
|
11279
|
+
printError({
|
|
11280
|
+
json: jsonOutput,
|
|
11281
|
+
code: "invalid_agents_dir",
|
|
11282
|
+
message: validation2.errorMessage,
|
|
11283
|
+
exitCode: 1
|
|
11284
|
+
});
|
|
11285
|
+
return null;
|
|
11286
|
+
}
|
|
11287
|
+
}
|
|
11288
|
+
const agentsDir = agentsDirResolution.resolvedPath;
|
|
11289
|
+
const homeDir = os.homedir();
|
|
11290
|
+
const { config } = await loadTargetConfig({ repoRoot, agentsDir });
|
|
11291
|
+
const validation = validateTargetConfig({ config, builtIns: BUILTIN_TARGETS });
|
|
11292
|
+
if (!validation.valid) {
|
|
11293
|
+
printError({
|
|
11294
|
+
json: jsonOutput,
|
|
11295
|
+
code: "invalid_target_config",
|
|
11296
|
+
message: `Invalid target configuration:
|
|
11297
|
+
- ${validation.errors.join("\n- ")}`,
|
|
11298
|
+
exitCode: 1
|
|
11299
|
+
});
|
|
11300
|
+
return null;
|
|
11301
|
+
}
|
|
11302
|
+
const resolved = resolveTargets({ config: validation.config, builtIns: BUILTIN_TARGETS });
|
|
11303
|
+
const targetResolver = createTargetNameResolver(resolved.targets);
|
|
11304
|
+
const usageCapableTargets = resolved.targets.filter((target) => target.usage);
|
|
11305
|
+
const supportedUsageTargetsMessage = formatSupportedUsageTargetsMessage(usageCapableTargets);
|
|
11306
|
+
const usingOnlySelection = onlyTargets.length > 0;
|
|
11307
|
+
const explicitTargetNames = positionalTargets[0] ? [positionalTargets[0]] : onlyTargets;
|
|
11308
|
+
let selectedTargets;
|
|
11309
|
+
const resolvedUsageCommands = /* @__PURE__ */ new Map();
|
|
11310
|
+
if (explicitTargetNames.length > 0) {
|
|
11311
|
+
const selectedIds = [];
|
|
11312
|
+
const unknownTargetNames = [];
|
|
11313
|
+
for (const targetName of explicitTargetNames) {
|
|
11314
|
+
const resolvedName = targetResolver.resolveTargetName(targetName);
|
|
11315
|
+
if (!resolvedName) {
|
|
11316
|
+
unknownTargetNames.push(targetName);
|
|
11317
|
+
continue;
|
|
11318
|
+
}
|
|
11319
|
+
if (!selectedIds.includes(resolvedName)) {
|
|
11320
|
+
selectedIds.push(resolvedName);
|
|
11321
|
+
}
|
|
11322
|
+
}
|
|
11323
|
+
if (unknownTargetNames.length > 0) {
|
|
11324
|
+
const unknownLabel = unknownTargetNames.join(", ");
|
|
11325
|
+
const message = usingOnlySelection ? `Unknown target name(s): ${unknownLabel}. ${supportedUsageTargetsMessage}` : `Unknown target: ${unknownLabel}. ${supportedUsageTargetsMessage}`;
|
|
11326
|
+
printError({
|
|
11327
|
+
json: jsonOutput,
|
|
11328
|
+
code: "unknown_target",
|
|
11329
|
+
message,
|
|
11330
|
+
exitCode: 2
|
|
11331
|
+
});
|
|
11332
|
+
return null;
|
|
11333
|
+
}
|
|
11334
|
+
const requestedTargets = selectedIds.flatMap((targetId) => {
|
|
11335
|
+
const target = resolved.byId.get(targetId.toLowerCase());
|
|
11336
|
+
return target ? [target] : [];
|
|
11337
|
+
});
|
|
11338
|
+
const unsupportedTargets = requestedTargets.filter((target) => !target.usage);
|
|
11339
|
+
if (unsupportedTargets.length > 0) {
|
|
11340
|
+
const unsupportedLabel = unsupportedTargets.map((target) => target.displayName).join(", ");
|
|
11341
|
+
printError({
|
|
11342
|
+
json: jsonOutput,
|
|
11343
|
+
code: "usage_unsupported",
|
|
11344
|
+
message: `${unsupportedLabel} does not support usage extraction. ${supportedUsageTargetsMessage}`,
|
|
11345
|
+
exitCode: 2,
|
|
11346
|
+
target: unsupportedTargets.length === 1 ? unsupportedTargets[0] : void 0
|
|
11347
|
+
});
|
|
11348
|
+
return null;
|
|
11349
|
+
}
|
|
11350
|
+
const requestedUsageIds = new Set(selectedIds);
|
|
11351
|
+
selectedTargets = usageCapableTargets.filter((target) => requestedUsageIds.has(target.id));
|
|
11352
|
+
const availabilityResults = await Promise.all(
|
|
11353
|
+
selectedTargets.map(async (target) => ({
|
|
11354
|
+
target,
|
|
11355
|
+
availability: await checkUsageCommandAvailability(target)
|
|
11356
|
+
}))
|
|
11357
|
+
);
|
|
11358
|
+
const unavailableResults = availabilityResults.filter(
|
|
11359
|
+
({ availability }) => availability.status !== "available"
|
|
11360
|
+
);
|
|
11361
|
+
if (unavailableResults.length > 0) {
|
|
11362
|
+
if (jsonOutput) {
|
|
11363
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
11364
|
+
const envelope2 = buildEnvelope({
|
|
11365
|
+
generatedAt: now2.toISOString(),
|
|
11366
|
+
targets: [],
|
|
11367
|
+
errors: unavailableResults.map(
|
|
11368
|
+
({ target, availability }) => buildError(target, "cli_unavailable", availability.reason ?? "CLI not found on PATH.")
|
|
11369
|
+
),
|
|
11370
|
+
notes: [],
|
|
11371
|
+
debug: debugOutput,
|
|
11372
|
+
debugArtifacts: []
|
|
11373
|
+
});
|
|
11374
|
+
console.log(JSON.stringify(envelope2, null, 2));
|
|
11375
|
+
} else if (unavailableResults.length === 1) {
|
|
11376
|
+
const unavailableResult = unavailableResults[0];
|
|
11377
|
+
if (unavailableResult) {
|
|
11378
|
+
const { target, availability } = unavailableResult;
|
|
11379
|
+
const message = availability.reason ?? "CLI not found on PATH.";
|
|
11380
|
+
console.error(
|
|
11381
|
+
`Error: ${target.displayName} usage extraction requires its CLI. ${message}`
|
|
11382
|
+
);
|
|
11383
|
+
}
|
|
11384
|
+
} else {
|
|
11385
|
+
console.error(
|
|
11386
|
+
[
|
|
11387
|
+
"Error: Some requested usage CLIs are unavailable:",
|
|
11388
|
+
...unavailableResults.map(({ target, availability }) => {
|
|
11389
|
+
const message = availability.reason ?? "CLI not found on PATH.";
|
|
11390
|
+
return `- ${target.displayName}: ${message}`;
|
|
11391
|
+
})
|
|
11392
|
+
].join("\n")
|
|
11393
|
+
);
|
|
11394
|
+
}
|
|
11395
|
+
process.exit(1);
|
|
11396
|
+
return null;
|
|
11397
|
+
}
|
|
11398
|
+
for (const { target, availability } of availabilityResults) {
|
|
11399
|
+
const resolvedCommand = availability.resolvedPath ?? availability.command;
|
|
11400
|
+
if (resolvedCommand) {
|
|
11401
|
+
resolvedUsageCommands.set(target.id, resolvedCommand);
|
|
11402
|
+
}
|
|
11403
|
+
}
|
|
11404
|
+
} else {
|
|
11405
|
+
const availabilityResults = await Promise.all(
|
|
11406
|
+
usageCapableTargets.map(async (target) => ({
|
|
11407
|
+
target,
|
|
11408
|
+
availability: await checkUsageCommandAvailability(target)
|
|
11409
|
+
}))
|
|
11410
|
+
);
|
|
11411
|
+
selectedTargets = [];
|
|
11412
|
+
for (const { target, availability } of availabilityResults) {
|
|
11413
|
+
if (availability.status !== "available") {
|
|
11414
|
+
continue;
|
|
11415
|
+
}
|
|
11416
|
+
selectedTargets.push(target);
|
|
11417
|
+
const resolvedCommand = availability.resolvedPath ?? availability.command;
|
|
11418
|
+
if (resolvedCommand) {
|
|
11419
|
+
resolvedUsageCommands.set(target.id, resolvedCommand);
|
|
11420
|
+
}
|
|
11421
|
+
}
|
|
11422
|
+
if (selectedTargets.length === 0) {
|
|
11423
|
+
const supportedUsageTargets = formatUsageTargetLabel(usageCapableTargets);
|
|
11424
|
+
const message = supportedUsageTargets ? `No installed active usage-capable agents were found. Install one of: ${supportedUsageTargets}.` : "No active usage-capable targets are enabled by the current target configuration.";
|
|
11425
|
+
if (jsonOutput) {
|
|
11426
|
+
const now2 = /* @__PURE__ */ new Date();
|
|
11427
|
+
const envelope2 = buildEnvelope({
|
|
11428
|
+
generatedAt: now2.toISOString(),
|
|
11429
|
+
targets: [],
|
|
11430
|
+
errors: [],
|
|
11431
|
+
notes: [message],
|
|
11432
|
+
debug: debugOutput,
|
|
11433
|
+
debugArtifacts: []
|
|
11434
|
+
});
|
|
11435
|
+
console.log(JSON.stringify(envelope2, null, 2));
|
|
11436
|
+
} else {
|
|
11437
|
+
console.log(message);
|
|
11438
|
+
}
|
|
11439
|
+
return {
|
|
11440
|
+
envelope: buildEnvelope({
|
|
11441
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11442
|
+
targets: [],
|
|
11443
|
+
errors: [],
|
|
11444
|
+
notes: [message],
|
|
11445
|
+
debug: debugOutput,
|
|
11446
|
+
debugArtifacts: []
|
|
11447
|
+
}),
|
|
11448
|
+
exitCode: 0,
|
|
11449
|
+
selectedTargets
|
|
11450
|
+
};
|
|
11451
|
+
}
|
|
11452
|
+
}
|
|
11453
|
+
const now = /* @__PURE__ */ new Date();
|
|
11454
|
+
const outcomes = await Promise.all(
|
|
11455
|
+
selectedTargets.map(
|
|
11456
|
+
(target) => extractUsageForTarget({
|
|
11457
|
+
target,
|
|
11458
|
+
repoRoot,
|
|
11459
|
+
agentsDir,
|
|
11460
|
+
homeDir,
|
|
11461
|
+
selectedWindow,
|
|
11462
|
+
timeoutMs: resolveTargetTimeoutMs(target, cliTimeoutMs),
|
|
11463
|
+
debug: debugOutput,
|
|
11464
|
+
now,
|
|
11465
|
+
command: resolvedUsageCommands.get(target.id)
|
|
11466
|
+
})
|
|
11467
|
+
)
|
|
11468
|
+
);
|
|
11469
|
+
const targets = [];
|
|
11470
|
+
const errors = [];
|
|
11471
|
+
const notes = [];
|
|
11472
|
+
const debugArtifacts = [];
|
|
11473
|
+
for (const outcome of outcomes) {
|
|
11474
|
+
if (outcome.status === "success") {
|
|
11475
|
+
targets.push(outcome.result);
|
|
11476
|
+
errors.push(...outcome.errors);
|
|
11477
|
+
notes.push(...outcome.notes);
|
|
11478
|
+
debugArtifacts.push(
|
|
11479
|
+
...outcome.debug.map((artifact) => ({
|
|
11480
|
+
...artifact,
|
|
11481
|
+
targetId: outcome.target.id,
|
|
11482
|
+
displayName: outcome.target.displayName
|
|
11483
|
+
}))
|
|
11484
|
+
);
|
|
11485
|
+
} else {
|
|
11486
|
+
errors.push(outcome.error);
|
|
11487
|
+
debugArtifacts.push(
|
|
11488
|
+
...outcome.debug.map((artifact) => ({
|
|
11489
|
+
...artifact,
|
|
11490
|
+
targetId: outcome.target.id,
|
|
11491
|
+
displayName: outcome.target.displayName
|
|
11492
|
+
}))
|
|
11493
|
+
);
|
|
11494
|
+
}
|
|
11495
|
+
}
|
|
11496
|
+
const envelope = buildEnvelope({
|
|
11497
|
+
generatedAt: now.toISOString(),
|
|
11498
|
+
targets,
|
|
11499
|
+
errors,
|
|
11500
|
+
notes,
|
|
11501
|
+
debug: debugOutput,
|
|
11502
|
+
debugArtifacts
|
|
11503
|
+
});
|
|
11504
|
+
const exitCode = errors.length > 0 ? 1 : 0;
|
|
11505
|
+
if (jsonOutput) {
|
|
11506
|
+
console.log(JSON.stringify(envelope, null, 2));
|
|
11507
|
+
} else {
|
|
11508
|
+
console.log(formatUsageTable(envelope, sortKey));
|
|
11509
|
+
}
|
|
11510
|
+
if (exitCode !== 0) {
|
|
11511
|
+
process.exit(exitCode);
|
|
11512
|
+
}
|
|
11513
|
+
return { envelope, exitCode, selectedTargets };
|
|
11514
|
+
}
|
|
11515
|
+
const usageCommand = {
|
|
11516
|
+
command: "usage [targets..]",
|
|
11517
|
+
describe: "Report usage limits for installed agent CLIs",
|
|
11518
|
+
builder: (yargsInstance) => yargsInstance.usage(
|
|
11519
|
+
"omniagent usage [target] [--only <targets>] [--sort <key>] [--window <window>] [--timeout <seconds>] [--agentsDir <path>] [--json] [--debug]"
|
|
11520
|
+
).positional("targets", {
|
|
11521
|
+
type: "string",
|
|
11522
|
+
array: true,
|
|
11523
|
+
describe: "Optional target id or alias."
|
|
11524
|
+
}).option("window", {
|
|
11525
|
+
type: "string",
|
|
11526
|
+
describe: "Filter usage rows by window (hourly, weekly, 5h, or a custom window)."
|
|
11527
|
+
}).option("only", {
|
|
11528
|
+
type: "string",
|
|
11529
|
+
describe: "Comma-separated target ids or aliases to report usage for."
|
|
11530
|
+
}).option("sort", {
|
|
11531
|
+
type: "string",
|
|
11532
|
+
describe: "Globally sort table rows by reset or left."
|
|
11533
|
+
}).option("timeout", {
|
|
11534
|
+
type: "string",
|
|
11535
|
+
describe: "Per-agent extraction timeout. Bare numbers are seconds; units include ms, s, and m."
|
|
11536
|
+
}).option("agentsDir", {
|
|
11537
|
+
type: "string",
|
|
11538
|
+
describe: "Override the agents directory (relative paths resolve from the project root)",
|
|
11539
|
+
defaultDescription: DEFAULT_AGENTS_DIR,
|
|
11540
|
+
coerce: (value) => {
|
|
11541
|
+
if (typeof value !== "string") {
|
|
11542
|
+
return value;
|
|
11543
|
+
}
|
|
11544
|
+
const trimmed = value.trim();
|
|
11545
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
11546
|
+
}
|
|
11547
|
+
}).option("json", {
|
|
11548
|
+
type: "boolean",
|
|
11549
|
+
describe: "Print a stable JSON envelope."
|
|
11550
|
+
}).option("debug", {
|
|
11551
|
+
type: "boolean",
|
|
11552
|
+
describe: "Print JSON and include extractor debug artifacts when available."
|
|
11553
|
+
}).epilog(
|
|
11554
|
+
"Usage extraction may launch agent TUIs and may incur cost if an agent reads repo context on startup. omniagent uses cheap/minimal launch settings where possible."
|
|
11555
|
+
),
|
|
11556
|
+
handler: async (argv) => {
|
|
11557
|
+
await runUsageCommand(argv);
|
|
11558
|
+
}
|
|
11559
|
+
};
|
|
10012
11560
|
const EXIT_CODES = {
|
|
10013
11561
|
success: 0,
|
|
10014
11562
|
"execution-error": 1,
|
|
@@ -10679,7 +12227,7 @@ function resolveVersion() {
|
|
|
10679
12227
|
return "0.0.0";
|
|
10680
12228
|
}
|
|
10681
12229
|
const VERSION = resolveVersion();
|
|
10682
|
-
const KNOWN_COMMANDS = /* @__PURE__ */ new Set(["hello", "greet", "echo", "sync", "dev", "profiles"]);
|
|
12230
|
+
const KNOWN_COMMANDS = /* @__PURE__ */ new Set(["hello", "greet", "echo", "sync", "dev", "profiles", "usage"]);
|
|
10683
12231
|
const SHIM_CAPABILITIES = [
|
|
10684
12232
|
"Capabilities by agent:",
|
|
10685
12233
|
" codex: approval, sandbox, output, model, web",
|
|
@@ -10729,7 +12277,7 @@ function runCli(argv = process.argv, options = {}) {
|
|
|
10729
12277
|
console.error(formatError(message, args));
|
|
10730
12278
|
const exitCode = isCommandInvocation(args) ? 1 : 2;
|
|
10731
12279
|
process.exit(exitCode);
|
|
10732
|
-
}).command(helloCommand).command(greetCommand).command(echoCommand).command(syncCommand).command(devCommand).command(profilesCommand).command(
|
|
12280
|
+
}).command(helloCommand).command(greetCommand).command(echoCommand).command(syncCommand).command(devCommand).command(profilesCommand).command(usageCommand).command(
|
|
10733
12281
|
"$0",
|
|
10734
12282
|
"omniagent CLI",
|
|
10735
12283
|
(yargsInstance) => yargsInstance.usage("omniagent [flags] --agent <target-id> [-- <agent flags>]").example("omniagent --agent codex", "Start an interactive session (default mode).").example('omniagent -p "Summarize the repo" --agent codex', "Run a one-shot prompt.").example("omniagent --agent codex -- --some-flag", "Pass through agent-specific flags.").option("prompt", {
|
|
@@ -10789,5 +12337,11 @@ if (!entry) {
|
|
|
10789
12337
|
}
|
|
10790
12338
|
}
|
|
10791
12339
|
export {
|
|
12340
|
+
compactLines as a,
|
|
12341
|
+
parsePercentRemaining as b,
|
|
12342
|
+
cleanControlOutput as c,
|
|
12343
|
+
parseResetText as d,
|
|
12344
|
+
makeUsageLimit as m,
|
|
12345
|
+
parsePercentUsed as p,
|
|
10792
12346
|
runCli
|
|
10793
12347
|
};
|