@charzhu/openjaw-agent 0.2.6 → 0.2.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 +1 -1
- package/config.yaml +2 -2
- package/dist/main.js +959 -336
- package/dist/main.js.map +4 -4
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -204,7 +204,7 @@ var init_config = __esm({
|
|
|
204
204
|
"src/config.ts"() {
|
|
205
205
|
"use strict";
|
|
206
206
|
init_packageRoot();
|
|
207
|
-
DEFAULT_COPILOT_OAUTH_CLIENT_ID = "
|
|
207
|
+
DEFAULT_COPILOT_OAUTH_CLIENT_ID = "Iv1.b507a08c87ecfe98";
|
|
208
208
|
DEFAULT_CONFIG = {
|
|
209
209
|
llm: {
|
|
210
210
|
provider: "anthropic",
|
|
@@ -1884,6 +1884,85 @@ var init_openai = __esm({
|
|
|
1884
1884
|
}
|
|
1885
1885
|
});
|
|
1886
1886
|
|
|
1887
|
+
// src/copilot-token.ts
|
|
1888
|
+
function normalizeCopilotEnterpriseDomain(value) {
|
|
1889
|
+
return value.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
1890
|
+
}
|
|
1891
|
+
function copilotApiBase(enterpriseUrl) {
|
|
1892
|
+
return enterpriseUrl ? `https://copilot-api.${normalizeCopilotEnterpriseDomain(enterpriseUrl)}` : "https://api.githubcopilot.com";
|
|
1893
|
+
}
|
|
1894
|
+
function copilotTokenEndpoint(enterpriseUrl) {
|
|
1895
|
+
if (!enterpriseUrl) return "https://api.github.com/copilot_internal/v2/token";
|
|
1896
|
+
const domain = normalizeCopilotEnterpriseDomain(enterpriseUrl);
|
|
1897
|
+
const apiDomain = domain.startsWith("api.") ? domain : `api.${domain}`;
|
|
1898
|
+
return `https://${apiDomain}/copilot_internal/v2/token`;
|
|
1899
|
+
}
|
|
1900
|
+
function decodeQueryComponent(value) {
|
|
1901
|
+
return decodeURIComponent(value.replace(/\+/g, "%20"));
|
|
1902
|
+
}
|
|
1903
|
+
function copilotApiBaseFromToken(token) {
|
|
1904
|
+
for (const part of token.split(";")) {
|
|
1905
|
+
const rawProxyEndpoint = part.startsWith("proxy-ep=") ? part.slice("proxy-ep=".length) : void 0;
|
|
1906
|
+
if (!rawProxyEndpoint) continue;
|
|
1907
|
+
const proxyEndpoint = decodeQueryComponent(rawProxyEndpoint).trim().replace(/\/+$/, "");
|
|
1908
|
+
if (!proxyEndpoint) return void 0;
|
|
1909
|
+
if (proxyEndpoint.startsWith("http://") || proxyEndpoint.startsWith("https://")) return proxyEndpoint;
|
|
1910
|
+
const host = proxyEndpoint.startsWith("proxy.") ? `api.${proxyEndpoint.slice("proxy.".length)}` : proxyEndpoint.startsWith("api.") ? proxyEndpoint : `api.${proxyEndpoint}`;
|
|
1911
|
+
return `https://${host}`;
|
|
1912
|
+
}
|
|
1913
|
+
return void 0;
|
|
1914
|
+
}
|
|
1915
|
+
async function exchangeGitHubTokenForCopilotToken(githubAccess, enterpriseUrl, signal) {
|
|
1916
|
+
const res = await fetch(copilotTokenEndpoint(enterpriseUrl), {
|
|
1917
|
+
headers: {
|
|
1918
|
+
"Accept": "application/json",
|
|
1919
|
+
"Authorization": `Bearer ${githubAccess}`,
|
|
1920
|
+
"User-Agent": COPILOT_USER_AGENT,
|
|
1921
|
+
"Editor-Version": COPILOT_EDITOR_VERSION,
|
|
1922
|
+
"Editor-Plugin-Version": COPILOT_EDITOR_PLUGIN_VERSION,
|
|
1923
|
+
"Copilot-Integration-Id": COPILOT_INTEGRATION_ID
|
|
1924
|
+
},
|
|
1925
|
+
signal
|
|
1926
|
+
});
|
|
1927
|
+
const text = await res.text();
|
|
1928
|
+
if (!res.ok) {
|
|
1929
|
+
let message = text;
|
|
1930
|
+
try {
|
|
1931
|
+
const parsed = JSON.parse(text);
|
|
1932
|
+
message = parsed.error_description || parsed.message || text;
|
|
1933
|
+
} catch {
|
|
1934
|
+
}
|
|
1935
|
+
throw new Error(`GitHub Copilot token request failed: ${res.status}${message ? ` ${message.slice(0, 160)}` : ""}`);
|
|
1936
|
+
}
|
|
1937
|
+
const body = JSON.parse(text);
|
|
1938
|
+
if (!body.token || typeof body.expires_at !== "number") {
|
|
1939
|
+
throw new Error("GitHub Copilot token response was missing token or expires_at.");
|
|
1940
|
+
}
|
|
1941
|
+
return {
|
|
1942
|
+
githubAccess,
|
|
1943
|
+
copilotAccess: body.token,
|
|
1944
|
+
copilotExpires: body.expires_at * 1e3,
|
|
1945
|
+
copilotApiBaseUrl: copilotApiBaseFromToken(body.token) ?? copilotApiBase(enterpriseUrl),
|
|
1946
|
+
enterpriseUrl
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
var COPILOT_USER_AGENT, COPILOT_EDITOR_VERSION, COPILOT_EDITOR_PLUGIN_VERSION, COPILOT_INTEGRATION_ID;
|
|
1950
|
+
var init_copilot_token = __esm({
|
|
1951
|
+
"src/copilot-token.ts"() {
|
|
1952
|
+
"use strict";
|
|
1953
|
+
COPILOT_USER_AGENT = "GitHubCopilotChat/0.35.0";
|
|
1954
|
+
COPILOT_EDITOR_VERSION = "vscode/1.107.0";
|
|
1955
|
+
COPILOT_EDITOR_PLUGIN_VERSION = "copilot-chat/0.35.0";
|
|
1956
|
+
COPILOT_INTEGRATION_ID = "vscode-chat";
|
|
1957
|
+
__name(normalizeCopilotEnterpriseDomain, "normalizeCopilotEnterpriseDomain");
|
|
1958
|
+
__name(copilotApiBase, "copilotApiBase");
|
|
1959
|
+
__name(copilotTokenEndpoint, "copilotTokenEndpoint");
|
|
1960
|
+
__name(decodeQueryComponent, "decodeQueryComponent");
|
|
1961
|
+
__name(copilotApiBaseFromToken, "copilotApiBaseFromToken");
|
|
1962
|
+
__name(exchangeGitHubTokenForCopilotToken, "exchangeGitHubTokenForCopilotToken");
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
|
|
1887
1966
|
// src/provider-auth.ts
|
|
1888
1967
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1889
1968
|
import { join as join5 } from "node:path";
|
|
@@ -2024,12 +2103,6 @@ var init_types = __esm({
|
|
|
2024
2103
|
});
|
|
2025
2104
|
|
|
2026
2105
|
// src/providers/copilot.ts
|
|
2027
|
-
function normalizeCopilotEnterpriseDomain(value) {
|
|
2028
|
-
return value.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
2029
|
-
}
|
|
2030
|
-
function copilotApiBase(enterpriseUrl) {
|
|
2031
|
-
return enterpriseUrl ? `https://copilot-api.${normalizeCopilotEnterpriseDomain(enterpriseUrl)}` : "https://api.githubcopilot.com";
|
|
2032
|
-
}
|
|
2033
2106
|
function shouldUseResponsesApi(modelID) {
|
|
2034
2107
|
const normalized = modelID.toLowerCase();
|
|
2035
2108
|
const match = /^gpt-(\d+)/.exec(normalized);
|
|
@@ -2079,6 +2152,12 @@ function toResponsesTool(tool) {
|
|
|
2079
2152
|
parameters: normalizeObjectSchema2(tool.parameters)
|
|
2080
2153
|
};
|
|
2081
2154
|
}
|
|
2155
|
+
function endpointSupported(endpoints, target) {
|
|
2156
|
+
return endpoints?.some((endpoint) => endpoint.trim().toLowerCase() === target) ?? false;
|
|
2157
|
+
}
|
|
2158
|
+
function copilotSupportsResponsesWebSocket(modelInfo) {
|
|
2159
|
+
return endpointSupported(modelInfo?.supportedEndpoints, "ws:/responses");
|
|
2160
|
+
}
|
|
2082
2161
|
function toAnthropicTool(tool) {
|
|
2083
2162
|
assertToolName(tool.name);
|
|
2084
2163
|
return {
|
|
@@ -2113,6 +2192,16 @@ function safeJsonParse(value) {
|
|
|
2113
2192
|
return {};
|
|
2114
2193
|
}
|
|
2115
2194
|
}
|
|
2195
|
+
async function loadWebSocket() {
|
|
2196
|
+
const { createRequire } = await import("node:module");
|
|
2197
|
+
return createRequire(import.meta.url)("ws");
|
|
2198
|
+
}
|
|
2199
|
+
function responsesWebSocketUrl(baseUrl) {
|
|
2200
|
+
const url = new URL(`${baseUrl.replace(/\/+$/, "")}/responses`);
|
|
2201
|
+
if (url.protocol === "https:") url.protocol = "wss:";
|
|
2202
|
+
else if (url.protocol === "http:") url.protocol = "ws:";
|
|
2203
|
+
return url.toString();
|
|
2204
|
+
}
|
|
2116
2205
|
function valueAtPath(value, path3) {
|
|
2117
2206
|
let current = value;
|
|
2118
2207
|
for (const key of path3) {
|
|
@@ -2121,6 +2210,24 @@ function valueAtPath(value, path3) {
|
|
|
2121
2210
|
}
|
|
2122
2211
|
return current;
|
|
2123
2212
|
}
|
|
2213
|
+
function firstStringAtAny(value, paths2) {
|
|
2214
|
+
for (const path3 of paths2) {
|
|
2215
|
+
const candidate = valueAtPath(value, path3);
|
|
2216
|
+
if (typeof candidate === "string" && candidate.trim()) return candidate;
|
|
2217
|
+
}
|
|
2218
|
+
return void 0;
|
|
2219
|
+
}
|
|
2220
|
+
function valueContainsAny(value, needles) {
|
|
2221
|
+
if (typeof value === "string") {
|
|
2222
|
+
const normalized = value.toLowerCase();
|
|
2223
|
+
return needles.some((needle) => normalized.includes(needle));
|
|
2224
|
+
}
|
|
2225
|
+
if (Array.isArray(value)) return value.some((item) => valueContainsAny(item, needles));
|
|
2226
|
+
if (value && typeof value === "object") {
|
|
2227
|
+
return Object.values(value).some((item) => valueContainsAny(item, needles));
|
|
2228
|
+
}
|
|
2229
|
+
return false;
|
|
2230
|
+
}
|
|
2124
2231
|
function firstPositiveIntegerAtAny(value, paths2) {
|
|
2125
2232
|
for (const path3 of paths2) {
|
|
2126
2233
|
const candidate = valueAtPath(value, path3);
|
|
@@ -2151,25 +2258,68 @@ function readCopilotOutputTokens(capabilities) {
|
|
|
2151
2258
|
function readCopilotReasoningEfforts(capabilities) {
|
|
2152
2259
|
return normalizeReasoningEfforts(valueAtPath(capabilities, ["supports", "reasoning_effort"]));
|
|
2153
2260
|
}
|
|
2261
|
+
function copilotModelItems(body) {
|
|
2262
|
+
if (Array.isArray(body.data) && body.data.length > 0) return body.data;
|
|
2263
|
+
if (Array.isArray(body.models)) return body.models;
|
|
2264
|
+
return [];
|
|
2265
|
+
}
|
|
2266
|
+
function isDisabledPolicyValue(value) {
|
|
2267
|
+
return ["disabled", "blocked", "denied", "unavailable", "off"].includes(value.toLowerCase());
|
|
2268
|
+
}
|
|
2269
|
+
function policyAllows(policy) {
|
|
2270
|
+
if (policy === void 0 || policy === null) return true;
|
|
2271
|
+
if (typeof policy === "boolean") return policy;
|
|
2272
|
+
if (typeof policy === "string") return !isDisabledPolicyValue(policy);
|
|
2273
|
+
if (!policy || typeof policy !== "object" || Array.isArray(policy)) return true;
|
|
2274
|
+
const record = policy;
|
|
2275
|
+
if (record.enabled === false) return false;
|
|
2276
|
+
return !["state", "status", "result"].some((key) => {
|
|
2277
|
+
const value = record[key];
|
|
2278
|
+
return typeof value === "string" && isDisabledPolicyValue(value);
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
function isChatCapable(model) {
|
|
2282
|
+
if (model.id?.toLowerCase().includes("embedding")) return false;
|
|
2283
|
+
if (!model.capabilities) return true;
|
|
2284
|
+
if (valueContainsAny(model.capabilities, ["embedding", "embeddings"])) return false;
|
|
2285
|
+
const kind = firstStringAtAny(model.capabilities, [["type"], ["kind"], ["family"]]);
|
|
2286
|
+
return !kind || !["embedding", "embeddings", "completion", "completions"].includes(kind.toLowerCase());
|
|
2287
|
+
}
|
|
2154
2288
|
function buildReasoning(effort, modelInfo) {
|
|
2155
2289
|
const supported = modelInfo?.supportedReasoningEfforts?.map((option) => option.effort) ?? [];
|
|
2156
2290
|
const selected = effort && supported.includes(effort) ? effort : void 0;
|
|
2157
2291
|
const effective = selected ?? modelInfo?.defaultReasoningEffort;
|
|
2158
2292
|
return effective ? { effort: effective } : void 0;
|
|
2159
2293
|
}
|
|
2294
|
+
function collectResponsesOutputItem(item, accumulator) {
|
|
2295
|
+
if (item.type === "message" && !accumulator.sawTextDelta) {
|
|
2296
|
+
for (const block of item.content ?? []) {
|
|
2297
|
+
if ((block.type === "output_text" || block.type === "text") && block.text) {
|
|
2298
|
+
accumulator.text = (accumulator.text ?? "") + block.text;
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
} else if (item.type === "function_call" && item.name) {
|
|
2302
|
+
accumulator.toolCalls.push({
|
|
2303
|
+
id: item.call_id || item.id || `call_${accumulator.toolCalls.length}`,
|
|
2304
|
+
name: item.name,
|
|
2305
|
+
input: safeJsonParse(item.arguments)
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2160
2309
|
function parseCopilotModels(body) {
|
|
2161
|
-
const items =
|
|
2310
|
+
const items = copilotModelItems(body);
|
|
2162
2311
|
const models = [];
|
|
2163
2312
|
for (const item of items) {
|
|
2164
|
-
if (!item.id || item.model_picker_enabled === false || item.policy
|
|
2165
|
-
const visionMedia = item.capabilities
|
|
2313
|
+
if (!item.id || item.model_picker_enabled === false || !policyAllows(item.policy) || !isChatCapable(item)) continue;
|
|
2314
|
+
const visionMedia = valueAtPath(item.capabilities, ["limits", "vision", "supported_media_types"]);
|
|
2166
2315
|
const supportedReasoning = readCopilotReasoningEfforts(item.capabilities);
|
|
2167
2316
|
models.push({
|
|
2168
2317
|
id: item.id,
|
|
2169
2318
|
name: item.name,
|
|
2170
2319
|
supportedEndpoints: item.supported_endpoints ?? [],
|
|
2171
|
-
|
|
2172
|
-
|
|
2320
|
+
supportsResponsesWebSocket: copilotSupportsResponsesWebSocket({ supportedEndpoints: item.supported_endpoints ?? [] }),
|
|
2321
|
+
supportsVision: valueAtPath(item.capabilities, ["supports", "vision"]) === true || Array.isArray(visionMedia) && visionMedia.some((media) => typeof media === "string" && media.startsWith("image/")),
|
|
2322
|
+
supportsToolCalls: valueAtPath(item.capabilities, ["supports", "tool_calls"]) !== false,
|
|
2173
2323
|
contextWindow: readCopilotContextWindow(item.capabilities),
|
|
2174
2324
|
outputTokens: readCopilotOutputTokens(item.capabilities),
|
|
2175
2325
|
supportedReasoningEfforts: supportedReasoning.map((effort) => ({ effort, description: effort })),
|
|
@@ -2178,32 +2328,46 @@ function parseCopilotModels(body) {
|
|
|
2178
2328
|
}
|
|
2179
2329
|
return models;
|
|
2180
2330
|
}
|
|
2181
|
-
var COPILOT_PROVIDER, USER_AGENT, OPENAI_TOOL_NAME2, CopilotProvider;
|
|
2331
|
+
var COPILOT_PROVIDER, USER_AGENT, OPENAI_TOOL_NAME2, COPILOT_TOKEN_EXPIRY_SAFETY_MARGIN_MS, RESPONSES_WEBSOCKET_CONNECT_TIMEOUT_MS, RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS, CopilotProvider;
|
|
2182
2332
|
var init_copilot = __esm({
|
|
2183
2333
|
"src/providers/copilot.ts"() {
|
|
2184
2334
|
"use strict";
|
|
2335
|
+
init_copilot_token();
|
|
2185
2336
|
init_provider_auth();
|
|
2186
2337
|
init_types();
|
|
2338
|
+
init_copilot_token();
|
|
2187
2339
|
COPILOT_PROVIDER = "github-copilot";
|
|
2188
2340
|
USER_AGENT = "openjaw-agent/0.1.0";
|
|
2189
2341
|
OPENAI_TOOL_NAME2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
2190
|
-
|
|
2191
|
-
|
|
2342
|
+
COPILOT_TOKEN_EXPIRY_SAFETY_MARGIN_MS = 6e4;
|
|
2343
|
+
RESPONSES_WEBSOCKET_CONNECT_TIMEOUT_MS = 1e4;
|
|
2344
|
+
RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS = 12e4;
|
|
2192
2345
|
__name(shouldUseResponsesApi, "shouldUseResponsesApi");
|
|
2193
2346
|
__name(normalizeObjectSchema2, "normalizeObjectSchema");
|
|
2194
2347
|
__name(assertToolName, "assertToolName");
|
|
2195
2348
|
__name(toChatTool, "toChatTool");
|
|
2196
2349
|
__name(toResponsesTool, "toResponsesTool");
|
|
2350
|
+
__name(endpointSupported, "endpointSupported");
|
|
2351
|
+
__name(copilotSupportsResponsesWebSocket, "copilotSupportsResponsesWebSocket");
|
|
2197
2352
|
__name(toAnthropicTool, "toAnthropicTool");
|
|
2198
2353
|
__name(hasImageContent, "hasImageContent");
|
|
2199
2354
|
__name(openAIUserContent, "openAIUserContent");
|
|
2200
2355
|
__name(safeJsonParse, "safeJsonParse");
|
|
2356
|
+
__name(loadWebSocket, "loadWebSocket");
|
|
2357
|
+
__name(responsesWebSocketUrl, "responsesWebSocketUrl");
|
|
2201
2358
|
__name(valueAtPath, "valueAtPath");
|
|
2359
|
+
__name(firstStringAtAny, "firstStringAtAny");
|
|
2360
|
+
__name(valueContainsAny, "valueContainsAny");
|
|
2202
2361
|
__name(firstPositiveIntegerAtAny, "firstPositiveIntegerAtAny");
|
|
2203
2362
|
__name(readCopilotContextWindow, "readCopilotContextWindow");
|
|
2204
2363
|
__name(readCopilotOutputTokens, "readCopilotOutputTokens");
|
|
2205
2364
|
__name(readCopilotReasoningEfforts, "readCopilotReasoningEfforts");
|
|
2365
|
+
__name(copilotModelItems, "copilotModelItems");
|
|
2366
|
+
__name(isDisabledPolicyValue, "isDisabledPolicyValue");
|
|
2367
|
+
__name(policyAllows, "policyAllows");
|
|
2368
|
+
__name(isChatCapable, "isChatCapable");
|
|
2206
2369
|
__name(buildReasoning, "buildReasoning");
|
|
2370
|
+
__name(collectResponsesOutputItem, "collectResponsesOutputItem");
|
|
2207
2371
|
__name(parseCopilotModels, "parseCopilotModels");
|
|
2208
2372
|
CopilotProvider = class {
|
|
2209
2373
|
static {
|
|
@@ -2212,6 +2376,7 @@ var init_copilot = __esm({
|
|
|
2212
2376
|
name = COPILOT_PROVIDER;
|
|
2213
2377
|
config;
|
|
2214
2378
|
modelCache = null;
|
|
2379
|
+
responsesWebSocketDisabled = false;
|
|
2215
2380
|
constructor(config) {
|
|
2216
2381
|
this.config = config;
|
|
2217
2382
|
}
|
|
@@ -2228,39 +2393,74 @@ var init_copilot = __esm({
|
|
|
2228
2393
|
}
|
|
2229
2394
|
async chat(options) {
|
|
2230
2395
|
const modelInfo = await this.resolveModelInfo(this.config.model);
|
|
2231
|
-
if (modelInfo?.supportedEndpoints.includes("/v1/messages") || this.config.model.toLowerCase().startsWith("claude-")) {
|
|
2232
|
-
return this.chatAnthropicMessages(options);
|
|
2233
|
-
}
|
|
2234
2396
|
if (this.shouldRouteToResponses(modelInfo)) {
|
|
2235
2397
|
return this.chatResponses(options, modelInfo);
|
|
2236
2398
|
}
|
|
2399
|
+
if (this.shouldRouteToAnthropicMessages(modelInfo)) {
|
|
2400
|
+
return this.chatAnthropicMessages(options);
|
|
2401
|
+
}
|
|
2237
2402
|
return this.chatCompletions(options);
|
|
2238
2403
|
}
|
|
2239
2404
|
shouldRouteToResponses(modelInfo) {
|
|
2240
2405
|
if (this.config.use_responses_api === false) return false;
|
|
2241
2406
|
if (modelInfo?.supportedEndpoints.length) {
|
|
2242
|
-
return modelInfo.supportedEndpoints
|
|
2407
|
+
return endpointSupported(modelInfo.supportedEndpoints, "/responses");
|
|
2243
2408
|
}
|
|
2244
2409
|
return shouldUseResponsesApi(this.config.model);
|
|
2245
2410
|
}
|
|
2411
|
+
shouldRouteToAnthropicMessages(modelInfo) {
|
|
2412
|
+
if (modelInfo?.supportedEndpoints.length) return false;
|
|
2413
|
+
return this.config.model.toLowerCase().startsWith("claude-");
|
|
2414
|
+
}
|
|
2415
|
+
copilotBaseUrl(credential) {
|
|
2416
|
+
if (this.config.base_url) return this.config.base_url.replace(/\/+$/, "");
|
|
2417
|
+
if (credential?.type === "oauth" && credential.copilotApiBaseUrl) return credential.copilotApiBaseUrl.replace(/\/+$/, "");
|
|
2418
|
+
const enterpriseUrl = this.config.copilot_enterprise_url || (credential?.type === "oauth" ? credential.enterpriseUrl : void 0);
|
|
2419
|
+
return copilotApiBase(enterpriseUrl);
|
|
2420
|
+
}
|
|
2421
|
+
async resolveCopilotAuth(signal) {
|
|
2422
|
+
if (this.config.api_key && this.config.api_key !== "proxy-token") {
|
|
2423
|
+
return { token: this.config.api_key, baseUrl: this.copilotBaseUrl() };
|
|
2424
|
+
}
|
|
2425
|
+
const credential = getProviderCredential(COPILOT_PROVIDER);
|
|
2426
|
+
if (credential?.type !== "oauth") {
|
|
2427
|
+
throw new Error("GitHub Copilot is not connected. Run /connect github-copilot first.");
|
|
2428
|
+
}
|
|
2429
|
+
if (credential.copilotAccess && credential.copilotExpires && credential.copilotExpires > Date.now() + COPILOT_TOKEN_EXPIRY_SAFETY_MARGIN_MS) {
|
|
2430
|
+
return { token: credential.copilotAccess, baseUrl: this.copilotBaseUrl(credential) };
|
|
2431
|
+
}
|
|
2432
|
+
const githubAccess = credential.githubAccess || credential.refresh || credential.access;
|
|
2433
|
+
const enterpriseUrl = this.config.copilot_enterprise_url || credential.enterpriseUrl;
|
|
2434
|
+
const exchanged = await exchangeGitHubTokenForCopilotToken(githubAccess, enterpriseUrl, signal);
|
|
2435
|
+
saveProviderCredential({
|
|
2436
|
+
...credential,
|
|
2437
|
+
access: exchanged.copilotAccess,
|
|
2438
|
+
refresh: exchanged.githubAccess,
|
|
2439
|
+
expires: exchanged.copilotExpires,
|
|
2440
|
+
githubAccess: exchanged.githubAccess,
|
|
2441
|
+
copilotAccess: exchanged.copilotAccess,
|
|
2442
|
+
copilotExpires: exchanged.copilotExpires,
|
|
2443
|
+
copilotApiBaseUrl: exchanged.copilotApiBaseUrl,
|
|
2444
|
+
enterpriseUrl
|
|
2445
|
+
});
|
|
2446
|
+
return { token: exchanged.copilotAccess, baseUrl: this.config.base_url?.replace(/\/+$/, "") ?? exchanged.copilotApiBaseUrl };
|
|
2447
|
+
}
|
|
2246
2448
|
resolveGitHubToken() {
|
|
2247
2449
|
if (this.config.api_key && this.config.api_key !== "proxy-token") return this.config.api_key;
|
|
2248
2450
|
const credential = getProviderCredential(COPILOT_PROVIDER);
|
|
2249
|
-
if (credential?.type === "oauth") return credential.
|
|
2451
|
+
if (credential?.type === "oauth") return credential.githubAccess || credential.refresh || credential.access;
|
|
2250
2452
|
throw new Error("GitHub Copilot is not connected. Run /connect github-copilot first.");
|
|
2251
2453
|
}
|
|
2252
|
-
resolveCopilotToken() {
|
|
2253
|
-
return this.
|
|
2454
|
+
async resolveCopilotToken(signal) {
|
|
2455
|
+
return (await this.resolveCopilotAuth(signal)).token;
|
|
2254
2456
|
}
|
|
2255
|
-
baseUrl() {
|
|
2256
|
-
|
|
2257
|
-
const credential = getProviderCredential(COPILOT_PROVIDER);
|
|
2258
|
-
const enterpriseUrl = this.config.copilot_enterprise_url || (credential?.type === "oauth" ? credential.enterpriseUrl : void 0);
|
|
2259
|
-
return copilotApiBase(enterpriseUrl);
|
|
2457
|
+
async baseUrl(signal) {
|
|
2458
|
+
return (await this.resolveCopilotAuth(signal)).baseUrl;
|
|
2260
2459
|
}
|
|
2261
|
-
async headers(options, extra) {
|
|
2460
|
+
async headers(options, extra, auth) {
|
|
2461
|
+
const resolvedAuth = auth ?? await this.resolveCopilotAuth(options.signal);
|
|
2262
2462
|
const headers = {
|
|
2263
|
-
"Authorization": `Bearer ${
|
|
2463
|
+
"Authorization": `Bearer ${resolvedAuth.token}`,
|
|
2264
2464
|
"Content-Type": "application/json",
|
|
2265
2465
|
"User-Agent": USER_AGENT,
|
|
2266
2466
|
"Editor-Version": "OpenJaw/0.1.0",
|
|
@@ -2274,15 +2474,17 @@ var init_copilot = __esm({
|
|
|
2274
2474
|
return headers;
|
|
2275
2475
|
}
|
|
2276
2476
|
async fetchModelInfo() {
|
|
2277
|
-
const
|
|
2477
|
+
const signal = AbortSignal.timeout(1e4);
|
|
2478
|
+
const auth = await this.resolveCopilotAuth(signal);
|
|
2479
|
+
const res = await fetch(`${auth.baseUrl}/models`, {
|
|
2278
2480
|
headers: {
|
|
2279
|
-
"Authorization": `Bearer ${
|
|
2481
|
+
"Authorization": `Bearer ${auth.token}`,
|
|
2280
2482
|
"User-Agent": USER_AGENT,
|
|
2281
2483
|
"Editor-Version": "OpenJaw/0.1.0",
|
|
2282
2484
|
"Editor-Plugin-Version": "OpenJaw/0.1.0",
|
|
2283
2485
|
"Copilot-Integration-Id": "vscode-chat"
|
|
2284
2486
|
},
|
|
2285
|
-
signal
|
|
2487
|
+
signal
|
|
2286
2488
|
});
|
|
2287
2489
|
if (!res.ok) {
|
|
2288
2490
|
const detail = await res.text().catch(() => "");
|
|
@@ -2304,6 +2506,7 @@ var init_copilot = __esm({
|
|
|
2304
2506
|
id: modelID,
|
|
2305
2507
|
name: modelID,
|
|
2306
2508
|
supportedEndpoints: ["/v1/messages"],
|
|
2509
|
+
supportsResponsesWebSocket: false,
|
|
2307
2510
|
supportsVision: true,
|
|
2308
2511
|
supportsToolCalls: true
|
|
2309
2512
|
};
|
|
@@ -2311,6 +2514,102 @@ var init_copilot = __esm({
|
|
|
2311
2514
|
return null;
|
|
2312
2515
|
}
|
|
2313
2516
|
}
|
|
2517
|
+
shouldUseResponsesWebSocket(modelInfo) {
|
|
2518
|
+
return !this.responsesWebSocketDisabled && copilotSupportsResponsesWebSocket(modelInfo);
|
|
2519
|
+
}
|
|
2520
|
+
disableResponsesWebSocket() {
|
|
2521
|
+
this.responsesWebSocketDisabled = true;
|
|
2522
|
+
}
|
|
2523
|
+
buildResponsesRequestBody(options, modelInfo) {
|
|
2524
|
+
const reasoning = buildReasoning(options.reasoningEffort, modelInfo);
|
|
2525
|
+
return {
|
|
2526
|
+
model: this.config.model,
|
|
2527
|
+
input: this.buildResponsesInput(options),
|
|
2528
|
+
instructions: Array.isArray(options.systemPrompt) ? options.systemPrompt.map((block) => block.text).join("\n\n") : options.systemPrompt,
|
|
2529
|
+
tools: options.tools.length > 0 ? options.tools.map(toResponsesTool) : void 0,
|
|
2530
|
+
...reasoning && { reasoning, include: ["reasoning.encrypted_content"] }
|
|
2531
|
+
};
|
|
2532
|
+
}
|
|
2533
|
+
buildResponsesWebSocketRequest(requestBody) {
|
|
2534
|
+
return {
|
|
2535
|
+
type: "response.create",
|
|
2536
|
+
...requestBody,
|
|
2537
|
+
tools: requestBody.tools ?? [],
|
|
2538
|
+
tool_choice: requestBody.tools?.length ? "auto" : "none",
|
|
2539
|
+
parallel_tool_calls: true,
|
|
2540
|
+
store: false,
|
|
2541
|
+
stream: true,
|
|
2542
|
+
include: requestBody.include ?? []
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
async chatResponsesWebSocket(options, requestBody) {
|
|
2546
|
+
const auth = await this.resolveCopilotAuth(options.signal);
|
|
2547
|
+
const headers = await this.headers(options, void 0, auth);
|
|
2548
|
+
const WebSocket2 = await loadWebSocket();
|
|
2549
|
+
const ws = new WebSocket2(responsesWebSocketUrl(auth.baseUrl), {
|
|
2550
|
+
headers,
|
|
2551
|
+
handshakeTimeout: RESPONSES_WEBSOCKET_CONNECT_TIMEOUT_MS
|
|
2552
|
+
});
|
|
2553
|
+
const request = JSON.stringify(this.buildResponsesWebSocketRequest(requestBody));
|
|
2554
|
+
return new Promise((resolve5, reject) => {
|
|
2555
|
+
const accumulator = { sawTextDelta: false, text: null, toolCalls: [] };
|
|
2556
|
+
let settled = false;
|
|
2557
|
+
const timeout = setTimeout(() => {
|
|
2558
|
+
if (settled) return;
|
|
2559
|
+
settled = true;
|
|
2560
|
+
ws.close();
|
|
2561
|
+
reject(new Error("Responses WebSocket idle timeout"));
|
|
2562
|
+
}, RESPONSES_WEBSOCKET_IDLE_TIMEOUT_MS);
|
|
2563
|
+
const finish = /* @__PURE__ */ __name((value) => {
|
|
2564
|
+
if (settled) return;
|
|
2565
|
+
settled = true;
|
|
2566
|
+
clearTimeout(timeout);
|
|
2567
|
+
ws.close();
|
|
2568
|
+
resolve5(value);
|
|
2569
|
+
}, "finish");
|
|
2570
|
+
const fail = /* @__PURE__ */ __name((error) => {
|
|
2571
|
+
if (settled) return;
|
|
2572
|
+
settled = true;
|
|
2573
|
+
clearTimeout(timeout);
|
|
2574
|
+
ws.close();
|
|
2575
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
2576
|
+
}, "fail");
|
|
2577
|
+
options.signal?.addEventListener("abort", () => fail(options.signal?.reason ?? new DOMException("Aborted", "AbortError")), { once: true });
|
|
2578
|
+
ws.addEventListener("open", () => ws.send(request));
|
|
2579
|
+
ws.addEventListener("error", (event) => fail(event.error ?? event.message ?? "Responses WebSocket error"));
|
|
2580
|
+
ws.addEventListener("close", (event) => {
|
|
2581
|
+
if (!settled) fail(new Error(`Responses WebSocket closed before completion (${event.code ?? "unknown"})`));
|
|
2582
|
+
});
|
|
2583
|
+
ws.addEventListener("message", (event) => {
|
|
2584
|
+
try {
|
|
2585
|
+
const text = typeof event.data === "string" ? event.data : Buffer.isBuffer(event.data) ? event.data.toString("utf8") : String(event.data);
|
|
2586
|
+
const parsed = JSON.parse(text);
|
|
2587
|
+
const type = String(parsed.type ?? "");
|
|
2588
|
+
if (type === "response.output_text.delta" && typeof parsed.delta === "string") {
|
|
2589
|
+
accumulator.sawTextDelta = true;
|
|
2590
|
+
accumulator.text = (accumulator.text ?? "") + parsed.delta;
|
|
2591
|
+
} else if (type === "response.output_item.done" && parsed.item && typeof parsed.item === "object") {
|
|
2592
|
+
collectResponsesOutputItem(parsed.item, accumulator);
|
|
2593
|
+
} else if (type === "response.failed") {
|
|
2594
|
+
fail(new Error(JSON.stringify(parsed.response ?? parsed)));
|
|
2595
|
+
} else if (type === "response.incomplete") {
|
|
2596
|
+
fail(new Error("Responses WebSocket returned incomplete response"));
|
|
2597
|
+
} else if (type === "response.completed") {
|
|
2598
|
+
const response = parsed.response && typeof parsed.response === "object" ? parsed.response : {};
|
|
2599
|
+
const usage2 = response.usage && typeof response.usage === "object" ? response.usage : void 0;
|
|
2600
|
+
finish({
|
|
2601
|
+
text: accumulator.text,
|
|
2602
|
+
toolCalls: accumulator.toolCalls,
|
|
2603
|
+
stopReason: accumulator.toolCalls.length > 0 ? "tool_use" : "end",
|
|
2604
|
+
usage: this.usage(usage2?.input_tokens, usage2?.output_tokens)
|
|
2605
|
+
});
|
|
2606
|
+
}
|
|
2607
|
+
} catch (error) {
|
|
2608
|
+
fail(error);
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2611
|
+
});
|
|
2612
|
+
}
|
|
2314
2613
|
buildChatMessages(options) {
|
|
2315
2614
|
const messages = [
|
|
2316
2615
|
{
|
|
@@ -2362,7 +2661,7 @@ var init_copilot = __esm({
|
|
|
2362
2661
|
tool_choice: options.tools.length > 0 ? "auto" : void 0,
|
|
2363
2662
|
temperature: this.config.temperature
|
|
2364
2663
|
};
|
|
2365
|
-
const res = await fetch(`${this.baseUrl()}/chat/completions`, {
|
|
2664
|
+
const res = await fetch(`${await this.baseUrl(options.signal)}/chat/completions`, {
|
|
2366
2665
|
method: "POST",
|
|
2367
2666
|
headers: await this.headers(options),
|
|
2368
2667
|
body: JSON.stringify(requestBody),
|
|
@@ -2406,15 +2705,16 @@ var init_copilot = __esm({
|
|
|
2406
2705
|
return input;
|
|
2407
2706
|
}
|
|
2408
2707
|
async chatResponses(options, modelInfo) {
|
|
2409
|
-
const
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2708
|
+
const requestBody = this.buildResponsesRequestBody(options, modelInfo);
|
|
2709
|
+
if (this.shouldUseResponsesWebSocket(modelInfo)) {
|
|
2710
|
+
try {
|
|
2711
|
+
return await this.chatResponsesWebSocket(options, requestBody);
|
|
2712
|
+
} catch (err) {
|
|
2713
|
+
if (options.signal?.aborted) throw err;
|
|
2714
|
+
this.disableResponsesWebSocket();
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2717
|
+
const res = await fetch(`${await this.baseUrl(options.signal)}/responses`, {
|
|
2418
2718
|
method: "POST",
|
|
2419
2719
|
headers: await this.headers(options),
|
|
2420
2720
|
body: JSON.stringify(requestBody),
|
|
@@ -2493,7 +2793,7 @@ var init_copilot = __esm({
|
|
|
2493
2793
|
messages: this.buildAnthropicMessages(options),
|
|
2494
2794
|
tools: options.tools.length > 0 ? options.tools.map(toAnthropicTool) : void 0
|
|
2495
2795
|
};
|
|
2496
|
-
const res = await fetch(`${this.baseUrl()}/v1/messages`, {
|
|
2796
|
+
const res = await fetch(`${await this.baseUrl(options.signal)}/v1/messages`, {
|
|
2497
2797
|
method: "POST",
|
|
2498
2798
|
headers: await this.headers(options, {
|
|
2499
2799
|
"anthropic-version": "2023-06-01",
|
|
@@ -2803,6 +3103,34 @@ var init_cost_tracker = __esm({
|
|
|
2803
3103
|
}
|
|
2804
3104
|
});
|
|
2805
3105
|
|
|
3106
|
+
// src/domain/usage.ts
|
|
3107
|
+
var ZERO, contextPercent, formatContextPercent;
|
|
3108
|
+
var init_usage = __esm({
|
|
3109
|
+
"src/domain/usage.ts"() {
|
|
3110
|
+
"use strict";
|
|
3111
|
+
ZERO = { calls: 0, input: 0, output: 0, total: 0 };
|
|
3112
|
+
contextPercent = /* @__PURE__ */ __name((used, max) => {
|
|
3113
|
+
if (!Number.isFinite(used) || !Number.isFinite(max) || used <= 0 || max <= 0) {
|
|
3114
|
+
return 0;
|
|
3115
|
+
}
|
|
3116
|
+
const raw = used / max * 100;
|
|
3117
|
+
return raw < 10 ? Math.round(raw * 10) / 10 : Math.round(raw);
|
|
3118
|
+
}, "contextPercent");
|
|
3119
|
+
formatContextPercent = /* @__PURE__ */ __name((pct) => {
|
|
3120
|
+
if (pct == null || !Number.isFinite(pct) || pct <= 0) {
|
|
3121
|
+
return "0%";
|
|
3122
|
+
}
|
|
3123
|
+
if (pct < 0.1) {
|
|
3124
|
+
return "<0.1%";
|
|
3125
|
+
}
|
|
3126
|
+
if (pct < 10) {
|
|
3127
|
+
return `${pct.toFixed(1).replace(/\.0$/, "")}%`;
|
|
3128
|
+
}
|
|
3129
|
+
return `${Math.round(pct)}%`;
|
|
3130
|
+
}, "formatContextPercent");
|
|
3131
|
+
}
|
|
3132
|
+
});
|
|
3133
|
+
|
|
2806
3134
|
// src/context-manager.ts
|
|
2807
3135
|
function contextKey(provider, model) {
|
|
2808
3136
|
return `${provider}\0${model}`;
|
|
@@ -2824,6 +3152,7 @@ var CONTEXT_WINDOWS, DEFAULT_CONTEXT_WINDOW, ContextManager;
|
|
|
2824
3152
|
var init_context_manager = __esm({
|
|
2825
3153
|
"src/context-manager.ts"() {
|
|
2826
3154
|
"use strict";
|
|
3155
|
+
init_usage();
|
|
2827
3156
|
CONTEXT_WINDOWS = {
|
|
2828
3157
|
"claude-sonnet-4": 2e5,
|
|
2829
3158
|
"claude-sonnet-4.5": 2e5,
|
|
@@ -2877,7 +3206,7 @@ var init_context_manager = __esm({
|
|
|
2877
3206
|
const liveContextWindow = this.activeProvider ? this.liveModelContextWindows.get(contextKey(this.activeProvider, model)) : void 0;
|
|
2878
3207
|
return getContextWindow(model, { contextWindow: liveContextWindow });
|
|
2879
3208
|
}
|
|
2880
|
-
/** Update from actual API response usage */
|
|
3209
|
+
/** Update latest effective context footprint from actual API response usage. */
|
|
2881
3210
|
updateFromUsage(usage2) {
|
|
2882
3211
|
this.lastTotalTokens = usage2.inputTokens + usage2.outputTokens + usage2.cacheReadTokens + usage2.cacheCreationTokens;
|
|
2883
3212
|
}
|
|
@@ -2897,7 +3226,7 @@ var init_context_manager = __esm({
|
|
|
2897
3226
|
/** Get context usage as percentage */
|
|
2898
3227
|
getUsagePercent(model) {
|
|
2899
3228
|
const limit = this.getContextWindow(model);
|
|
2900
|
-
return
|
|
3229
|
+
return contextPercent(this.lastTotalTokens, limit);
|
|
2901
3230
|
}
|
|
2902
3231
|
/** Format context display string */
|
|
2903
3232
|
formatContext(model) {
|
|
@@ -3796,13 +4125,18 @@ async function completeCopilotDeviceFlow(flow, signal) {
|
|
|
3796
4125
|
}
|
|
3797
4126
|
const body = await res.json();
|
|
3798
4127
|
if (body.access_token) {
|
|
4128
|
+
const copilotToken = await exchangeGitHubTokenForCopilotToken(body.access_token, flow.enterpriseUrl, signal);
|
|
3799
4129
|
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
3800
4130
|
saveProviderCredential({
|
|
3801
4131
|
type: "oauth",
|
|
3802
4132
|
provider: "github-copilot",
|
|
3803
|
-
access:
|
|
3804
|
-
refresh:
|
|
3805
|
-
expires:
|
|
4133
|
+
access: copilotToken.copilotAccess,
|
|
4134
|
+
refresh: copilotToken.githubAccess,
|
|
4135
|
+
expires: copilotToken.copilotExpires,
|
|
4136
|
+
githubAccess: copilotToken.githubAccess,
|
|
4137
|
+
copilotAccess: copilotToken.copilotAccess,
|
|
4138
|
+
copilotExpires: copilotToken.copilotExpires,
|
|
4139
|
+
copilotApiBaseUrl: copilotToken.copilotApiBaseUrl,
|
|
3806
4140
|
enterpriseUrl: flow.enterpriseUrl,
|
|
3807
4141
|
createdAt: now2,
|
|
3808
4142
|
updatedAt: now2
|
|
@@ -3810,7 +4144,7 @@ async function completeCopilotDeviceFlow(flow, signal) {
|
|
|
3810
4144
|
return {
|
|
3811
4145
|
provider: "github-copilot",
|
|
3812
4146
|
enterpriseUrl: flow.enterpriseUrl,
|
|
3813
|
-
baseUrl:
|
|
4147
|
+
baseUrl: copilotToken.copilotApiBaseUrl
|
|
3814
4148
|
};
|
|
3815
4149
|
}
|
|
3816
4150
|
if (body.error === "authorization_pending") continue;
|
|
@@ -3826,7 +4160,7 @@ var init_copilot_auth = __esm({
|
|
|
3826
4160
|
"src/copilot-auth.ts"() {
|
|
3827
4161
|
"use strict";
|
|
3828
4162
|
init_provider_auth();
|
|
3829
|
-
|
|
4163
|
+
init_copilot_token();
|
|
3830
4164
|
OAUTH_POLLING_SAFETY_MARGIN_MS = 3e3;
|
|
3831
4165
|
__name(isOAuthAbortError, "isOAuthAbortError");
|
|
3832
4166
|
__name(oauthDomain, "oauthDomain");
|
|
@@ -8977,9 +9311,9 @@ var init_outlook_graph = __esm({
|
|
|
8977
9311
|
const wellKnown = WELL_KNOWN_FOLDERS[lower];
|
|
8978
9312
|
if (wellKnown)
|
|
8979
9313
|
return wellKnown;
|
|
8980
|
-
const
|
|
8981
|
-
if (
|
|
8982
|
-
return
|
|
9314
|
+
const cached7 = this.folderIdCache.get(lower);
|
|
9315
|
+
if (cached7)
|
|
9316
|
+
return cached7;
|
|
8983
9317
|
try {
|
|
8984
9318
|
const result = await this.graphGet(`/me/mailFolders?$filter=displayName eq '${folderName.replace(/'/g, "''")}'&$top=1`);
|
|
8985
9319
|
if (result.value.length > 0) {
|
|
@@ -9337,9 +9671,9 @@ var init_db = __esm({
|
|
|
9337
9671
|
import { createHash as createHash2 } from "node:crypto";
|
|
9338
9672
|
function encodeAtom(word, dim2 = HRR_DIM) {
|
|
9339
9673
|
const cacheKey = `${word}:${dim2}`;
|
|
9340
|
-
const
|
|
9341
|
-
if (
|
|
9342
|
-
return
|
|
9674
|
+
const cached7 = atomCache.get(cacheKey);
|
|
9675
|
+
if (cached7)
|
|
9676
|
+
return cached7;
|
|
9343
9677
|
const phases = new Float64Array(dim2);
|
|
9344
9678
|
const bytesNeeded = dim2 * 4;
|
|
9345
9679
|
const chunks = [];
|
|
@@ -12555,9 +12889,9 @@ ${loopContent}` : loopContent;
|
|
|
12555
12889
|
*/
|
|
12556
12890
|
async findChannelByName(searchTerm) {
|
|
12557
12891
|
const searchLower = searchTerm.toLowerCase();
|
|
12558
|
-
const
|
|
12559
|
-
if (
|
|
12560
|
-
return { ...
|
|
12892
|
+
const cached7 = this.channelIdCache.get(searchLower);
|
|
12893
|
+
if (cached7) {
|
|
12894
|
+
return { ...cached7, displayName: searchTerm };
|
|
12561
12895
|
}
|
|
12562
12896
|
try {
|
|
12563
12897
|
const teamsData = await this.graphGet("/v1.0/me/joinedTeams");
|
|
@@ -12737,9 +13071,9 @@ ${loopContent}` : loopContent;
|
|
|
12737
13071
|
* Results are cached per chat ID.
|
|
12738
13072
|
*/
|
|
12739
13073
|
async getChatMembers(chatOrChannelId) {
|
|
12740
|
-
const
|
|
12741
|
-
if (
|
|
12742
|
-
return
|
|
13074
|
+
const cached7 = this.chatMembersCache.get(chatOrChannelId);
|
|
13075
|
+
if (cached7)
|
|
13076
|
+
return cached7;
|
|
12743
13077
|
try {
|
|
12744
13078
|
let endpoint;
|
|
12745
13079
|
if (this.contextType === "channel" && this.currentChannelTeamId && chatOrChannelId === this.currentChannelId) {
|
|
@@ -12977,9 +13311,9 @@ ${loopContent}` : loopContent;
|
|
|
12977
13311
|
*/
|
|
12978
13312
|
async resolveChannelIds(teamName, channelName) {
|
|
12979
13313
|
const cacheKey = `${teamName}/${channelName}`;
|
|
12980
|
-
const
|
|
12981
|
-
if (
|
|
12982
|
-
return
|
|
13314
|
+
const cached7 = this.channelIdCache.get(cacheKey);
|
|
13315
|
+
if (cached7)
|
|
13316
|
+
return cached7;
|
|
12983
13317
|
const teamsData = await this.graphGet("/v1.0/me/joinedTeams");
|
|
12984
13318
|
const team = teamsData.value?.find((t) => t.displayName.toLowerCase() === teamName.toLowerCase());
|
|
12985
13319
|
if (!team) {
|
|
@@ -19971,38 +20305,64 @@ var init_frontmatter = __esm({
|
|
|
19971
20305
|
});
|
|
19972
20306
|
|
|
19973
20307
|
// src/skills/registry.ts
|
|
19974
|
-
import { existsSync as existsSync14, readFileSync as readFileSync14, readdirSync as readdirSync2 } from "node:fs";
|
|
20308
|
+
import { existsSync as existsSync14, readFileSync as readFileSync14, readdirSync as readdirSync2, statSync } from "node:fs";
|
|
19975
20309
|
import { join as join22 } from "node:path";
|
|
19976
20310
|
import { homedir as homedir12 } from "node:os";
|
|
20311
|
+
function skillRoots() {
|
|
20312
|
+
return rootsOverride ?? { bundledDir: packageSkillsDir(), userDir: DEFAULT_USER_DIR };
|
|
20313
|
+
}
|
|
19977
20314
|
function discoverSkills() {
|
|
19978
|
-
|
|
20315
|
+
const signature = buildRegistrySignature();
|
|
20316
|
+
if (cachedSkills?.signature === signature) return cachedSkills.skills;
|
|
20317
|
+
const roots = skillRoots();
|
|
19979
20318
|
const byName2 = /* @__PURE__ */ new Map();
|
|
19980
|
-
|
|
19981
|
-
|
|
19982
|
-
|
|
19983
|
-
|
|
20319
|
+
loadFlatSkillsFromDir(roots.bundledDir, "bundled", 0, byName2);
|
|
20320
|
+
loadFlatSkillsFromDir(roots.userDir, "user", 1, byName2);
|
|
20321
|
+
loadPackagedSkillsFromDir(roots.userDir, byName2);
|
|
20322
|
+
const skills = [...byName2.values()].map((entry) => entry.skill).sort((a, b) => a.name.localeCompare(b.name));
|
|
20323
|
+
cachedSkills = { signature, skills };
|
|
20324
|
+
return skills;
|
|
19984
20325
|
}
|
|
19985
20326
|
function loadSkillBody(skillName) {
|
|
19986
|
-
const
|
|
19987
|
-
const skill = skills.find((s) => s.name === skillName);
|
|
20327
|
+
const skill = findSkill(skillName);
|
|
19988
20328
|
if (!skill) return null;
|
|
19989
20329
|
try {
|
|
19990
20330
|
const content = readFileSync14(skill.filePath, "utf-8").trim();
|
|
19991
|
-
const parsed = parseSkillFile(content, skill.name
|
|
20331
|
+
const parsed = parseSkillFile(content, `${skill.name}.md`);
|
|
19992
20332
|
return parsed.body;
|
|
19993
20333
|
} catch {
|
|
19994
20334
|
return null;
|
|
19995
20335
|
}
|
|
19996
20336
|
}
|
|
20337
|
+
function loadSkillPrompt(skillName) {
|
|
20338
|
+
const skill = findSkill(skillName);
|
|
20339
|
+
const body = skill ? loadSkillBody(skill.name) : null;
|
|
20340
|
+
if (!skill || !body) return null;
|
|
20341
|
+
return `# Skill Runtime Context
|
|
20342
|
+
|
|
20343
|
+
Skill name: ${skill.name}
|
|
20344
|
+
Skill file: ${skill.filePath}
|
|
20345
|
+
Skill root directory: ${skill.rootDir}
|
|
20346
|
+
|
|
20347
|
+
${body}`;
|
|
20348
|
+
}
|
|
19997
20349
|
function findSkill(name) {
|
|
19998
20350
|
const skills = discoverSkills();
|
|
19999
|
-
const
|
|
20351
|
+
const normalized = normalizeSkillName(name);
|
|
20352
|
+
const exact = skills.find((s) => s.name === normalized);
|
|
20000
20353
|
if (exact) return exact;
|
|
20001
|
-
const
|
|
20002
|
-
const ci = skills.find((s) => s.name.toLowerCase() === lower);
|
|
20354
|
+
const ci = skills.find((s) => s.name.toLowerCase() === normalized.toLowerCase());
|
|
20003
20355
|
if (ci) return ci;
|
|
20004
|
-
const
|
|
20005
|
-
return
|
|
20356
|
+
const matches = findSkillMatches(normalized);
|
|
20357
|
+
return matches.length === 1 ? matches[0] : null;
|
|
20358
|
+
}
|
|
20359
|
+
function findSkillMatches(name) {
|
|
20360
|
+
const normalized = normalizeSkillName(name).toLowerCase();
|
|
20361
|
+
if (!normalized) return [];
|
|
20362
|
+
return discoverSkills().filter((skill) => {
|
|
20363
|
+
const skillName = skill.name.toLowerCase();
|
|
20364
|
+
return skillName.startsWith(normalized) || normalized.startsWith(skillName);
|
|
20365
|
+
});
|
|
20006
20366
|
}
|
|
20007
20367
|
function getSkillListing() {
|
|
20008
20368
|
const skills = discoverSkills();
|
|
@@ -20017,52 +20377,145 @@ function getSkillListing() {
|
|
|
20017
20377
|
function clearSkillRegistry() {
|
|
20018
20378
|
cachedSkills = null;
|
|
20019
20379
|
}
|
|
20020
|
-
function
|
|
20021
|
-
|
|
20380
|
+
function normalizeSkillName(name) {
|
|
20381
|
+
return name.trim().replace(/^\/+/, "").toLowerCase();
|
|
20382
|
+
}
|
|
20383
|
+
function loadFlatSkillsFromDir(dir2, source, priority, out) {
|
|
20384
|
+
for (const entry of safeReadDir(dir2)) {
|
|
20385
|
+
if (!entry.isFile() || !isMarkdown(entry.name)) continue;
|
|
20386
|
+
const filePath = join22(dir2, entry.name);
|
|
20387
|
+
const skill = parseSkillAtPath(filePath, dir2, entry.name, source, entry.name);
|
|
20388
|
+
if (skill) putSkill(out, skill, priority);
|
|
20389
|
+
}
|
|
20390
|
+
}
|
|
20391
|
+
function loadPackagedSkillsFromDir(dir2, out) {
|
|
20392
|
+
for (const entry of safeReadDir(dir2)) {
|
|
20393
|
+
if (!entry.isDirectory()) continue;
|
|
20394
|
+
const rootDir = join22(dir2, entry.name);
|
|
20395
|
+
const entrypoint = findPackageEntrypoint(rootDir);
|
|
20396
|
+
if (!entrypoint) continue;
|
|
20397
|
+
const filePath = join22(rootDir, entrypoint);
|
|
20398
|
+
const skill = parseSkillAtPath(filePath, rootDir, entrypoint, "user", `${entry.name}.md`);
|
|
20399
|
+
if (skill) putSkill(out, skill, 2);
|
|
20400
|
+
}
|
|
20401
|
+
}
|
|
20402
|
+
function findPackageEntrypoint(dir2) {
|
|
20403
|
+
const entries = safeReadDir(dir2).filter((entry) => entry.isFile());
|
|
20404
|
+
const entrypoint = ENTRYPOINT_NAMES.find((name) => entries.some((entry) => entry.name.toLowerCase() === name.toLowerCase()));
|
|
20405
|
+
if (entrypoint) return entries.find((entry) => entry.name.toLowerCase() === entrypoint.toLowerCase())?.name ?? entrypoint;
|
|
20406
|
+
const readme = entries.find((entry) => entry.name.toLowerCase() === "readme.md");
|
|
20407
|
+
if (readme) return readme.name;
|
|
20408
|
+
const markdown = entries.filter((entry) => isMarkdown(entry.name));
|
|
20409
|
+
return markdown.length === 1 ? markdown[0].name : null;
|
|
20410
|
+
}
|
|
20411
|
+
function parseSkillAtPath(filePath, rootDir, entrypoint, source, fallbackFilename) {
|
|
20022
20412
|
try {
|
|
20023
|
-
const
|
|
20024
|
-
|
|
20025
|
-
|
|
20026
|
-
|
|
20027
|
-
|
|
20028
|
-
|
|
20029
|
-
|
|
20030
|
-
|
|
20031
|
-
|
|
20032
|
-
|
|
20033
|
-
|
|
20034
|
-
|
|
20035
|
-
|
|
20036
|
-
|
|
20037
|
-
|
|
20413
|
+
const content = readFileSync14(filePath, "utf-8").trim();
|
|
20414
|
+
if (!content) return null;
|
|
20415
|
+
const parsed = parseSkillFile(content, fallbackFilename);
|
|
20416
|
+
const name = normalizeSkillName(parsed.meta.name);
|
|
20417
|
+
if (!name) return null;
|
|
20418
|
+
return {
|
|
20419
|
+
name,
|
|
20420
|
+
meta: { ...parsed.meta, name },
|
|
20421
|
+
filePath,
|
|
20422
|
+
rootDir,
|
|
20423
|
+
entrypoint,
|
|
20424
|
+
source,
|
|
20425
|
+
hasFrontmatter: parsed.hasFrontmatter
|
|
20426
|
+
};
|
|
20427
|
+
} catch {
|
|
20428
|
+
return null;
|
|
20429
|
+
}
|
|
20430
|
+
}
|
|
20431
|
+
function putSkill(out, skill, priority) {
|
|
20432
|
+
const existing = out.get(skill.name);
|
|
20433
|
+
if (!existing || priority >= existing.priority) {
|
|
20434
|
+
out.set(skill.name, { priority, skill });
|
|
20435
|
+
}
|
|
20436
|
+
}
|
|
20437
|
+
function safeReadDir(dir2) {
|
|
20438
|
+
if (!existsSync14(dir2)) return [];
|
|
20439
|
+
try {
|
|
20440
|
+
return readdirSync2(dir2, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
20441
|
+
} catch {
|
|
20442
|
+
return [];
|
|
20443
|
+
}
|
|
20444
|
+
}
|
|
20445
|
+
function buildRegistrySignature() {
|
|
20446
|
+
const roots = skillRoots();
|
|
20447
|
+
return [signatureForDir(roots.bundledDir), signatureForDir(roots.userDir)].join("|");
|
|
20448
|
+
}
|
|
20449
|
+
function signatureForDir(dir2) {
|
|
20450
|
+
if (!existsSync14(dir2)) return `${dir2}:missing`;
|
|
20451
|
+
const parts = [];
|
|
20452
|
+
try {
|
|
20453
|
+
for (const entry of safeReadDir(dir2)) {
|
|
20454
|
+
const fullPath = join22(dir2, entry.name);
|
|
20455
|
+
if (entry.isFile()) {
|
|
20456
|
+
if (!isMarkdown(entry.name)) continue;
|
|
20457
|
+
parts.push(fileSignature(fullPath, `f:${entry.name}`));
|
|
20458
|
+
} else if (entry.isDirectory()) {
|
|
20459
|
+
parts.push(fileSignature(fullPath, `d:${entry.name}`));
|
|
20460
|
+
for (const child of safeReadDir(fullPath)) {
|
|
20461
|
+
if (child.isFile() && isMarkdown(child.name)) {
|
|
20462
|
+
parts.push(fileSignature(join22(fullPath, child.name), `d:${entry.name}/${child.name}`));
|
|
20463
|
+
}
|
|
20464
|
+
}
|
|
20038
20465
|
}
|
|
20039
20466
|
}
|
|
20040
20467
|
} catch {
|
|
20468
|
+
return `${dir2}:unreadable`;
|
|
20469
|
+
}
|
|
20470
|
+
return `${dir2}:${parts.join(",")}`;
|
|
20471
|
+
}
|
|
20472
|
+
function isMarkdown(name) {
|
|
20473
|
+
return name.toLowerCase().endsWith(".md");
|
|
20474
|
+
}
|
|
20475
|
+
function fileSignature(path3, label) {
|
|
20476
|
+
try {
|
|
20477
|
+
const stat2 = statSync(path3);
|
|
20478
|
+
return `${label}:${stat2.mtimeMs}:${stat2.size}`;
|
|
20479
|
+
} catch {
|
|
20480
|
+
return `${label}:missing`;
|
|
20041
20481
|
}
|
|
20042
20482
|
}
|
|
20043
|
-
var
|
|
20483
|
+
var DEFAULT_USER_DIR, ENTRYPOINT_NAMES, cachedSkills, rootsOverride;
|
|
20044
20484
|
var init_registry2 = __esm({
|
|
20045
20485
|
"src/skills/registry.ts"() {
|
|
20046
20486
|
"use strict";
|
|
20047
20487
|
init_frontmatter();
|
|
20048
20488
|
init_packageRoot();
|
|
20049
|
-
|
|
20489
|
+
DEFAULT_USER_DIR = join22(homedir12(), ".openjaw-agent", "skills");
|
|
20490
|
+
ENTRYPOINT_NAMES = ["SKILL.md", "skill.md"];
|
|
20050
20491
|
cachedSkills = null;
|
|
20492
|
+
rootsOverride = null;
|
|
20493
|
+
__name(skillRoots, "skillRoots");
|
|
20051
20494
|
__name(discoverSkills, "discoverSkills");
|
|
20052
20495
|
__name(loadSkillBody, "loadSkillBody");
|
|
20496
|
+
__name(loadSkillPrompt, "loadSkillPrompt");
|
|
20053
20497
|
__name(findSkill, "findSkill");
|
|
20498
|
+
__name(findSkillMatches, "findSkillMatches");
|
|
20054
20499
|
__name(getSkillListing, "getSkillListing");
|
|
20055
20500
|
__name(clearSkillRegistry, "clearSkillRegistry");
|
|
20056
|
-
__name(
|
|
20501
|
+
__name(normalizeSkillName, "normalizeSkillName");
|
|
20502
|
+
__name(loadFlatSkillsFromDir, "loadFlatSkillsFromDir");
|
|
20503
|
+
__name(loadPackagedSkillsFromDir, "loadPackagedSkillsFromDir");
|
|
20504
|
+
__name(findPackageEntrypoint, "findPackageEntrypoint");
|
|
20505
|
+
__name(parseSkillAtPath, "parseSkillAtPath");
|
|
20506
|
+
__name(putSkill, "putSkill");
|
|
20507
|
+
__name(safeReadDir, "safeReadDir");
|
|
20508
|
+
__name(buildRegistrySignature, "buildRegistrySignature");
|
|
20509
|
+
__name(signatureForDir, "signatureForDir");
|
|
20510
|
+
__name(isMarkdown, "isMarkdown");
|
|
20511
|
+
__name(fileSignature, "fileSignature");
|
|
20057
20512
|
}
|
|
20058
20513
|
});
|
|
20059
20514
|
|
|
20060
20515
|
// src/prompts/skills.ts
|
|
20061
20516
|
function getSkillsSection() {
|
|
20062
|
-
if (cached7 !== void 0) return cached7;
|
|
20063
20517
|
const skills = discoverSkills();
|
|
20064
20518
|
if (skills.length === 0) {
|
|
20065
|
-
cached7 = null;
|
|
20066
20519
|
return null;
|
|
20067
20520
|
}
|
|
20068
20521
|
const listing = getSkillListing();
|
|
@@ -20077,15 +20530,17 @@ New skills must be saved to \`~/.openjaw-agent/skills/\` (user skills directory)
|
|
|
20077
20530
|
Do NOT write skills to the project's bundled skills/ directory.
|
|
20078
20531
|
|
|
20079
20532
|
${listing}`;
|
|
20080
|
-
|
|
20081
|
-
|
|
20533
|
+
return content;
|
|
20534
|
+
}
|
|
20535
|
+
function clearSkillsCache() {
|
|
20536
|
+
clearSkillRegistry();
|
|
20082
20537
|
}
|
|
20083
|
-
var cached7;
|
|
20084
20538
|
var init_skills = __esm({
|
|
20085
20539
|
"src/prompts/skills.ts"() {
|
|
20086
20540
|
"use strict";
|
|
20087
20541
|
init_registry2();
|
|
20088
20542
|
__name(getSkillsSection, "getSkillsSection");
|
|
20543
|
+
__name(clearSkillsCache, "clearSkillsCache");
|
|
20089
20544
|
}
|
|
20090
20545
|
});
|
|
20091
20546
|
|
|
@@ -20776,8 +21231,8 @@ Options: ${chunk.choices.join(" | ")}` : "";
|
|
|
20776
21231
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
20777
21232
|
if (existsSync16(resolvedPath)) {
|
|
20778
21233
|
try {
|
|
20779
|
-
const { statSync:
|
|
20780
|
-
const stat2 =
|
|
21234
|
+
const { statSync: statSync5 } = await import("node:fs");
|
|
21235
|
+
const stat2 = statSync5(resolvedPath);
|
|
20781
21236
|
if (stat2.isFile() && stat2.size < 50 * 1024 * 1024) {
|
|
20782
21237
|
const ext = resolvedPath.split(".").pop()?.toLowerCase() || "";
|
|
20783
21238
|
const contentType = MIME_TYPES[ext] || "application/octet-stream";
|
|
@@ -21629,10 +22084,10 @@ var init_mcp_client = __esm({
|
|
|
21629
22084
|
let tokenExpiry = 0;
|
|
21630
22085
|
if (copilotTokenFile) {
|
|
21631
22086
|
try {
|
|
21632
|
-
const
|
|
21633
|
-
cachedToken =
|
|
21634
|
-
cachedRefreshToken =
|
|
21635
|
-
tokenExpiry =
|
|
22087
|
+
const cached7 = JSON.parse(readFileSync17(copilotTokenFile, "utf-8"));
|
|
22088
|
+
cachedToken = cached7.accessToken;
|
|
22089
|
+
cachedRefreshToken = cached7.refreshToken;
|
|
22090
|
+
tokenExpiry = cached7.expiresAt || 0;
|
|
21636
22091
|
} catch {
|
|
21637
22092
|
}
|
|
21638
22093
|
}
|
|
@@ -21771,11 +22226,31 @@ async function runCopilotResponsesSearch(input, llm, startedAt) {
|
|
|
21771
22226
|
if (!credential || credential.type !== "oauth") {
|
|
21772
22227
|
throw new Error("GitHub Copilot is not connected. Run /connect github-copilot first.");
|
|
21773
22228
|
}
|
|
21774
|
-
|
|
22229
|
+
let copilotAccess = credential.copilotAccess;
|
|
22230
|
+
let copilotApiBaseUrl = credential.copilotApiBaseUrl;
|
|
22231
|
+
if (!copilotAccess || !credential.copilotExpires || credential.copilotExpires <= Date.now() + COPILOT_TOKEN_EXPIRY_SAFETY_MARGIN_MS2) {
|
|
22232
|
+
const exchanged = await exchangeGitHubTokenForCopilotToken(
|
|
22233
|
+
credential.githubAccess || credential.refresh || credential.access,
|
|
22234
|
+
credential.enterpriseUrl
|
|
22235
|
+
);
|
|
22236
|
+
copilotAccess = exchanged.copilotAccess;
|
|
22237
|
+
copilotApiBaseUrl = exchanged.copilotApiBaseUrl;
|
|
22238
|
+
saveProviderCredential({
|
|
22239
|
+
...credential,
|
|
22240
|
+
access: exchanged.copilotAccess,
|
|
22241
|
+
refresh: exchanged.githubAccess,
|
|
22242
|
+
expires: exchanged.copilotExpires,
|
|
22243
|
+
githubAccess: exchanged.githubAccess,
|
|
22244
|
+
copilotAccess: exchanged.copilotAccess,
|
|
22245
|
+
copilotExpires: exchanged.copilotExpires,
|
|
22246
|
+
copilotApiBaseUrl: exchanged.copilotApiBaseUrl
|
|
22247
|
+
});
|
|
22248
|
+
}
|
|
22249
|
+
const baseUrl = llm.base_url?.replace(/\/+$/, "") ?? copilotApiBaseUrl?.replace(/\/+$/, "") ?? copilotApiBase(credential.enterpriseUrl);
|
|
21775
22250
|
const headers = {
|
|
21776
|
-
"Authorization": `Bearer ${
|
|
22251
|
+
"Authorization": `Bearer ${copilotAccess}`,
|
|
21777
22252
|
"Content-Type": "application/json",
|
|
21778
|
-
"User-Agent":
|
|
22253
|
+
"User-Agent": COPILOT_USER_AGENT2,
|
|
21779
22254
|
"Editor-Version": "OpenJaw/0.1.0",
|
|
21780
22255
|
"Editor-Plugin-Version": "OpenJaw/0.1.0",
|
|
21781
22256
|
"Copilot-Integration-Id": "vscode-chat",
|
|
@@ -22002,15 +22477,16 @@ function limitAndDedupe(results, max) {
|
|
|
22002
22477
|
function truncate(text) {
|
|
22003
22478
|
return text.length > 200 ? text.slice(0, 200) + "\u2026" : text;
|
|
22004
22479
|
}
|
|
22005
|
-
var
|
|
22480
|
+
var COPILOT_USER_AGENT2, DEFAULT_TIMEOUT_MS, COPILOT_TOKEN_EXPIRY_SAFETY_MARGIN_MS2;
|
|
22006
22481
|
var init_web_search = __esm({
|
|
22007
22482
|
"src/web-search.ts"() {
|
|
22008
22483
|
"use strict";
|
|
22009
22484
|
init_web_search_types();
|
|
22485
|
+
init_copilot_token();
|
|
22010
22486
|
init_provider_auth();
|
|
22011
|
-
|
|
22012
|
-
COPILOT_USER_AGENT = "openjaw-agent/0.1.0";
|
|
22487
|
+
COPILOT_USER_AGENT2 = "openjaw-agent/0.1.0";
|
|
22013
22488
|
DEFAULT_TIMEOUT_MS = 45e3;
|
|
22489
|
+
COPILOT_TOKEN_EXPIRY_SAFETY_MARGIN_MS2 = 6e4;
|
|
22014
22490
|
__name(createWebSearchExecutor, "createWebSearchExecutor");
|
|
22015
22491
|
__name(runCopilotResponsesSearch, "runCopilotResponsesSearch");
|
|
22016
22492
|
__name(runOpenAIResponsesSearch, "runOpenAIResponsesSearch");
|
|
@@ -26423,7 +26899,7 @@ function createSkillTool(config, toolRegistry, systemPromptFn) {
|
|
|
26423
26899
|
};
|
|
26424
26900
|
}
|
|
26425
26901
|
async function executeSkill(skillName, args, config, toolRegistry, systemPromptFn) {
|
|
26426
|
-
const body =
|
|
26902
|
+
const body = loadSkillPrompt(skillName);
|
|
26427
26903
|
if (!body) {
|
|
26428
26904
|
return { success: false, error: `Could not load skill content for "${skillName}"` };
|
|
26429
26905
|
}
|
|
@@ -26786,8 +27262,8 @@ var init_teams = __esm({
|
|
|
26786
27262
|
if (fileName.startsWith("oj-") || fileName.endsWith(".log") || fileName.endsWith(".tmp")) continue;
|
|
26787
27263
|
if (existsSync25(filePath)) {
|
|
26788
27264
|
try {
|
|
26789
|
-
const { statSync:
|
|
26790
|
-
const stat2 =
|
|
27265
|
+
const { statSync: statSync5 } = await import("node:fs");
|
|
27266
|
+
const stat2 = statSync5(filePath);
|
|
26791
27267
|
if (stat2.isFile() && stat2.size < 50 * 1024 * 1024) {
|
|
26792
27268
|
await this.sendFileToSelfChat(filePath);
|
|
26793
27269
|
sentFiles.add(filePath);
|
|
@@ -27346,8 +27822,8 @@ var init_feishu = __esm({
|
|
|
27346
27822
|
this.emit({ type: "system", content: `\u{1F50D} Found path: ${filePath} (exists: ${exists})` });
|
|
27347
27823
|
if (exists) {
|
|
27348
27824
|
try {
|
|
27349
|
-
const { statSync:
|
|
27350
|
-
const stat2 =
|
|
27825
|
+
const { statSync: statSync5 } = await import("node:fs");
|
|
27826
|
+
const stat2 = statSync5(filePath);
|
|
27351
27827
|
if (stat2.isFile() && stat2.size < 30 * 1024 * 1024) {
|
|
27352
27828
|
const fileType = this.getFeishuFileType(fileName);
|
|
27353
27829
|
this.emit({ type: "system", content: `\u{1F4E4} Uploading to Feishu: ${fileName} (${(stat2.size / 1024).toFixed(0)}KB, type=${fileType})` });
|
|
@@ -27443,7 +27919,7 @@ __export(wechat_exports, {
|
|
|
27443
27919
|
sniffMediaKind: () => sniffMediaKind,
|
|
27444
27920
|
validateMediaForUpload: () => validateMediaForUpload
|
|
27445
27921
|
});
|
|
27446
|
-
import { existsSync as existsSync27, readFileSync as readFileSync26, writeFileSync as writeFileSync18, unlinkSync as unlinkSync7, statSync as
|
|
27922
|
+
import { existsSync as existsSync27, readFileSync as readFileSync26, writeFileSync as writeFileSync18, unlinkSync as unlinkSync7, statSync as statSync3 } from "node:fs";
|
|
27447
27923
|
import { mkdirSync as mkdirSync16 } from "node:fs";
|
|
27448
27924
|
import { extname as extname3, join as join35 } from "node:path";
|
|
27449
27925
|
import { homedir as homedir21 } from "node:os";
|
|
@@ -28314,7 +28790,7 @@ Scan URL manually: ${qrUrl}` });
|
|
|
28314
28790
|
attemptedFiles.add(dedupKey);
|
|
28315
28791
|
attempted++;
|
|
28316
28792
|
try {
|
|
28317
|
-
const stat2 =
|
|
28793
|
+
const stat2 = statSync3(filePath);
|
|
28318
28794
|
if (!stat2.isFile() || stat2.size > 30 * 1024 * 1024) continue;
|
|
28319
28795
|
if (stat2.size === 0) {
|
|
28320
28796
|
this.emit({ type: "system", content: `\u26A0 WeChat skipped empty file: ${fileName}` });
|
|
@@ -29314,12 +29790,40 @@ var init_bootstrap = __esm({
|
|
|
29314
29790
|
}
|
|
29315
29791
|
});
|
|
29316
29792
|
|
|
29793
|
+
// src/usageSnapshot.ts
|
|
29794
|
+
function usageSnapshot(agentLoop) {
|
|
29795
|
+
const cost = agentLoop.costTracker.getSessionCost();
|
|
29796
|
+
const contextMax = agentLoop.contextManager.getContextWindow(agentLoop.model);
|
|
29797
|
+
const contextUsed = agentLoop.contextManager.lastPromptTokens;
|
|
29798
|
+
return {
|
|
29799
|
+
cache_read: cost.totalCacheReadTokens,
|
|
29800
|
+
cache_write: cost.totalCacheCreationTokens,
|
|
29801
|
+
calls: cost.turns,
|
|
29802
|
+
context_max: contextMax,
|
|
29803
|
+
context_percent: contextPercent(contextUsed, contextMax),
|
|
29804
|
+
context_used: contextUsed,
|
|
29805
|
+
cost_status: "estimated",
|
|
29806
|
+
cost_usd: cost.totalCostUSD,
|
|
29807
|
+
input: cost.totalInputTokens,
|
|
29808
|
+
model: agentLoop.model,
|
|
29809
|
+
output: cost.totalOutputTokens,
|
|
29810
|
+
total: cost.totalInputTokens + cost.totalOutputTokens + cost.totalCacheReadTokens + cost.totalCacheCreationTokens
|
|
29811
|
+
};
|
|
29812
|
+
}
|
|
29813
|
+
var init_usageSnapshot = __esm({
|
|
29814
|
+
"src/usageSnapshot.ts"() {
|
|
29815
|
+
"use strict";
|
|
29816
|
+
init_usage();
|
|
29817
|
+
__name(usageSnapshot, "usageSnapshot");
|
|
29818
|
+
}
|
|
29819
|
+
});
|
|
29820
|
+
|
|
29317
29821
|
// src/eventBridge.ts
|
|
29318
29822
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
29319
29823
|
async function streamAgentRun(options) {
|
|
29320
29824
|
const { agentLoop, bus, imageData, systemPrompt, text } = options;
|
|
29321
29825
|
const sid = agentLoop.sessionId;
|
|
29322
|
-
const state = newState();
|
|
29826
|
+
const state = newState(agentLoop);
|
|
29323
29827
|
bus.emitEvent({
|
|
29324
29828
|
payload: { kind: "thinking", text: "thinking\u2026" },
|
|
29325
29829
|
session_id: sid,
|
|
@@ -29409,11 +29913,13 @@ function translateChunk(chunk, state, bus, sid) {
|
|
|
29409
29913
|
}
|
|
29410
29914
|
}
|
|
29411
29915
|
}
|
|
29412
|
-
var newState, ensureMessageOpen, closeMessage;
|
|
29916
|
+
var newState, ensureMessageOpen, closeMessage, safeUsageSnapshot;
|
|
29413
29917
|
var init_eventBridge = __esm({
|
|
29414
29918
|
"src/eventBridge.ts"() {
|
|
29415
29919
|
"use strict";
|
|
29416
|
-
|
|
29920
|
+
init_usageSnapshot();
|
|
29921
|
+
newState = /* @__PURE__ */ __name((agentLoop) => ({
|
|
29922
|
+
agentLoop,
|
|
29417
29923
|
messageOpen: false,
|
|
29418
29924
|
pendingAnswer: "",
|
|
29419
29925
|
toolIds: /* @__PURE__ */ new Map()
|
|
@@ -29426,8 +29932,9 @@ var init_eventBridge = __esm({
|
|
|
29426
29932
|
}, "ensureMessageOpen");
|
|
29427
29933
|
closeMessage = /* @__PURE__ */ __name((state, bus, sid, text) => {
|
|
29428
29934
|
if (state.messageOpen || text) {
|
|
29935
|
+
const usage2 = safeUsageSnapshot(state.agentLoop);
|
|
29429
29936
|
bus.emitEvent({
|
|
29430
|
-
payload: { text: text ?? state.pendingAnswer },
|
|
29937
|
+
payload: { text: text ?? state.pendingAnswer, ...usage2 ? { usage: usage2 } : {} },
|
|
29431
29938
|
session_id: sid,
|
|
29432
29939
|
type: "message.complete"
|
|
29433
29940
|
});
|
|
@@ -29435,6 +29942,13 @@ var init_eventBridge = __esm({
|
|
|
29435
29942
|
state.pendingAnswer = "";
|
|
29436
29943
|
}
|
|
29437
29944
|
}, "closeMessage");
|
|
29945
|
+
safeUsageSnapshot = /* @__PURE__ */ __name((agentLoop) => {
|
|
29946
|
+
try {
|
|
29947
|
+
return usageSnapshot(agentLoop);
|
|
29948
|
+
} catch {
|
|
29949
|
+
return void 0;
|
|
29950
|
+
}
|
|
29951
|
+
}, "safeUsageSnapshot");
|
|
29438
29952
|
__name(streamAgentRun, "streamAgentRun");
|
|
29439
29953
|
__name(translateChunk, "translateChunk");
|
|
29440
29954
|
}
|
|
@@ -29514,15 +30028,6 @@ var init_env = __esm({
|
|
|
29514
30028
|
}
|
|
29515
30029
|
});
|
|
29516
30030
|
|
|
29517
|
-
// src/domain/usage.ts
|
|
29518
|
-
var ZERO;
|
|
29519
|
-
var init_usage = __esm({
|
|
29520
|
-
"src/domain/usage.ts"() {
|
|
29521
|
-
"use strict";
|
|
29522
|
-
ZERO = { calls: 0, input: 0, output: 0, total: 0 };
|
|
29523
|
-
}
|
|
29524
|
-
});
|
|
29525
|
-
|
|
29526
30031
|
// src/theme.ts
|
|
29527
30032
|
function parseHex(h) {
|
|
29528
30033
|
const m = /^#?([0-9a-f]{6})$/i.exec(h);
|
|
@@ -29692,6 +30197,14 @@ function normalizeThemeForAnsiLightTerminal(theme, env2 = process.env, isLight =
|
|
|
29692
30197
|
}
|
|
29693
30198
|
return { ...theme, color };
|
|
29694
30199
|
}
|
|
30200
|
+
function isBuiltinSkinName(value) {
|
|
30201
|
+
return BUILTIN_SKINS.some((skin) => skin.name === value);
|
|
30202
|
+
}
|
|
30203
|
+
function themeForBuiltinSkin(name) {
|
|
30204
|
+
if (name === "dark") return DARK_THEME;
|
|
30205
|
+
if (name === "light") return LIGHT_THEME;
|
|
30206
|
+
return DEFAULT_THEME;
|
|
30207
|
+
}
|
|
29695
30208
|
function fromSkin(colors, branding, bannerLogo = "", bannerHero = "", toolPrefix = "", helpHeader = "") {
|
|
29696
30209
|
const d = DEFAULT_THEME;
|
|
29697
30210
|
const c = /* @__PURE__ */ __name((k) => colors[k], "c");
|
|
@@ -29749,7 +30262,7 @@ function fromSkin(colors, branding, bannerLogo = "", bannerHero = "", toolPrefix
|
|
|
29749
30262
|
bannerHero
|
|
29750
30263
|
}, process.env, DEFAULT_LIGHT_MODE);
|
|
29751
30264
|
}
|
|
29752
|
-
var XTERM_6_LEVELS, ANSI_LIGHT_MAX_LUMINANCE, ANSI_LIGHT_TARGET_LUMINANCE, ANSI_LIGHT_MIN_SATURATION, ANSI_MUTED_BUCKET, ANSI_NORMALIZED_FOREGROUNDS, ANSI_MUTED_FOREGROUNDS, BRAND, cleanPromptSymbol, DARK_THEME, LIGHT_THEME, TRUE_RE2, FALSE_RE2, LIGHT_DEFAULT_TERM_PROGRAMS, LUMA_LIGHT_THRESHOLD, HEX_3_RE, HEX_6_RE, DEFAULT_LIGHT_MODE, DEFAULT_THEME;
|
|
30265
|
+
var XTERM_6_LEVELS, ANSI_LIGHT_MAX_LUMINANCE, ANSI_LIGHT_TARGET_LUMINANCE, ANSI_LIGHT_MIN_SATURATION, ANSI_MUTED_BUCKET, ANSI_NORMALIZED_FOREGROUNDS, ANSI_MUTED_FOREGROUNDS, BRAND, cleanPromptSymbol, DARK_THEME, LIGHT_THEME, TRUE_RE2, FALSE_RE2, LIGHT_DEFAULT_TERM_PROGRAMS, LUMA_LIGHT_THRESHOLD, HEX_3_RE, HEX_6_RE, DEFAULT_LIGHT_MODE, DEFAULT_THEME, BUILTIN_SKINS;
|
|
29753
30266
|
var init_theme = __esm({
|
|
29754
30267
|
"src/theme.ts"() {
|
|
29755
30268
|
"use strict";
|
|
@@ -29901,6 +30414,13 @@ var init_theme = __esm({
|
|
|
29901
30414
|
process.env,
|
|
29902
30415
|
DEFAULT_LIGHT_MODE
|
|
29903
30416
|
);
|
|
30417
|
+
BUILTIN_SKINS = [
|
|
30418
|
+
{ name: "default", description: "Auto-detect terminal light/dark preference" },
|
|
30419
|
+
{ name: "dark", description: "OpenJaw dark coral theme" },
|
|
30420
|
+
{ name: "light", description: "Light terminal theme" }
|
|
30421
|
+
];
|
|
30422
|
+
__name(isBuiltinSkinName, "isBuiltinSkinName");
|
|
30423
|
+
__name(themeForBuiltinSkin, "themeForBuiltinSkin");
|
|
29904
30424
|
__name(fromSkin, "fromSkin");
|
|
29905
30425
|
}
|
|
29906
30426
|
});
|
|
@@ -31669,11 +32189,11 @@ function sliceAnsi(str, start, end) {
|
|
|
31669
32189
|
}
|
|
31670
32190
|
if (end !== void 0) {
|
|
31671
32191
|
const key = `${start}|${end}|${str}`;
|
|
31672
|
-
const
|
|
31673
|
-
if (
|
|
32192
|
+
const cached7 = sliceCache.get(key);
|
|
32193
|
+
if (cached7 !== void 0) {
|
|
31674
32194
|
sliceCache.delete(key);
|
|
31675
|
-
sliceCache.set(key,
|
|
31676
|
-
return
|
|
32195
|
+
sliceCache.set(key, cached7);
|
|
32196
|
+
return cached7;
|
|
31677
32197
|
}
|
|
31678
32198
|
const result = computeSlice(str, start, end);
|
|
31679
32199
|
if (sliceCache.size >= SLICE_CACHE_LIMIT) {
|
|
@@ -31728,11 +32248,11 @@ function computeSlice(str, start, end) {
|
|
|
31728
32248
|
return result;
|
|
31729
32249
|
}
|
|
31730
32250
|
function lineWidth(line) {
|
|
31731
|
-
const
|
|
31732
|
-
if (
|
|
32251
|
+
const cached7 = cache.get(line);
|
|
32252
|
+
if (cached7 !== void 0) {
|
|
31733
32253
|
cache.delete(line);
|
|
31734
|
-
cache.set(line,
|
|
31735
|
-
return
|
|
32254
|
+
cache.set(line, cached7);
|
|
32255
|
+
return cached7;
|
|
31736
32256
|
}
|
|
31737
32257
|
const width = stringWidth(line);
|
|
31738
32258
|
if (cache.size >= MAX_CACHE_SIZE) {
|
|
@@ -31749,11 +32269,11 @@ function evictLineWidthCache(keepRatio = 0) {
|
|
|
31749
32269
|
}
|
|
31750
32270
|
function memoizedWrap(text, maxWidth, wrapType) {
|
|
31751
32271
|
const key = `${maxWidth}|${wrapType}|${text}`;
|
|
31752
|
-
const
|
|
31753
|
-
if (
|
|
32272
|
+
const cached7 = wrapCache.get(key);
|
|
32273
|
+
if (cached7 !== void 0) {
|
|
31754
32274
|
wrapCache.delete(key);
|
|
31755
|
-
wrapCache.set(key,
|
|
31756
|
-
return
|
|
32275
|
+
wrapCache.set(key, cached7);
|
|
32276
|
+
return cached7;
|
|
31757
32277
|
}
|
|
31758
32278
|
const result = computeWrap(text, maxWidth, wrapType);
|
|
31759
32279
|
if (wrapCache.size >= WRAP_CACHE_LIMIT) {
|
|
@@ -33713,9 +34233,9 @@ function collectRemovedRects(parent, removed, underAbsolute = false) {
|
|
|
33713
34233
|
}
|
|
33714
34234
|
const elem = removed;
|
|
33715
34235
|
const isAbsolute2 = underAbsolute || elem.style.position === "absolute";
|
|
33716
|
-
const
|
|
33717
|
-
if (
|
|
33718
|
-
addPendingClear(parent,
|
|
34236
|
+
const cached7 = nodeCache.get(elem);
|
|
34237
|
+
if (cached7) {
|
|
34238
|
+
addPendingClear(parent, cached7, isAbsolute2);
|
|
33719
34239
|
nodeCache.delete(elem);
|
|
33720
34240
|
}
|
|
33721
34241
|
for (const child of elem.childNodes) {
|
|
@@ -35835,31 +36355,31 @@ function renderNodeToOutput(node, output, {
|
|
|
35835
36355
|
if (y < 0 && node.style.position === "absolute") {
|
|
35836
36356
|
y = 0;
|
|
35837
36357
|
}
|
|
35838
|
-
const
|
|
35839
|
-
if (!node.dirty && !skipSelfBlit && node.pendingScrollDelta === void 0 &&
|
|
36358
|
+
const cached7 = nodeCache.get(node);
|
|
36359
|
+
if (!node.dirty && !skipSelfBlit && node.pendingScrollDelta === void 0 && cached7 && cached7.x === x && cached7.y === y && cached7.width === width && cached7.height === height && prevScreen) {
|
|
35840
36360
|
const fx = Math.floor(x);
|
|
35841
36361
|
const fy = Math.floor(y);
|
|
35842
36362
|
const fw = Math.floor(width);
|
|
35843
36363
|
const fh = Math.floor(height);
|
|
35844
36364
|
output.blit(prevScreen, fx, fy, fw, fh);
|
|
35845
36365
|
if (node.style.position === "absolute") {
|
|
35846
|
-
absoluteRectsCur.push(
|
|
36366
|
+
absoluteRectsCur.push(cached7);
|
|
35847
36367
|
}
|
|
35848
36368
|
blitEscapingAbsoluteDescendants(node, output, prevScreen, fx, fy, fw, fh);
|
|
35849
36369
|
return;
|
|
35850
36370
|
}
|
|
35851
|
-
const positionChanged =
|
|
36371
|
+
const positionChanged = cached7 !== void 0 && (cached7.x !== x || cached7.y !== y || cached7.width !== width || cached7.height !== height);
|
|
35852
36372
|
if (positionChanged) {
|
|
35853
36373
|
layoutShifted = true;
|
|
35854
36374
|
absoluteOverlayMoved ||= node.style.position === "absolute";
|
|
35855
36375
|
}
|
|
35856
|
-
if (
|
|
36376
|
+
if (cached7 && (node.dirty || positionChanged)) {
|
|
35857
36377
|
output.clear(
|
|
35858
36378
|
{
|
|
35859
|
-
x: Math.floor(
|
|
35860
|
-
y: Math.floor(
|
|
35861
|
-
width: Math.floor(
|
|
35862
|
-
height: Math.floor(
|
|
36379
|
+
x: Math.floor(cached7.x),
|
|
36380
|
+
y: Math.floor(cached7.y),
|
|
36381
|
+
width: Math.floor(cached7.width),
|
|
36382
|
+
height: Math.floor(cached7.height)
|
|
35863
36383
|
},
|
|
35864
36384
|
node.style.position === "absolute"
|
|
35865
36385
|
);
|
|
@@ -36034,7 +36554,7 @@ function renderNodeToOutput(node, output, {
|
|
|
36034
36554
|
const delta = contentCached.y - contentY;
|
|
36035
36555
|
const regionTop = Math.floor(y + contentYoga.getComputedTop());
|
|
36036
36556
|
const regionBottom = regionTop + innerHeight - 1;
|
|
36037
|
-
if (
|
|
36557
|
+
if (cached7?.y === y && cached7.height === height && innerHeight > 0 && Math.abs(delta) < innerHeight) {
|
|
36038
36558
|
hint = { top: regionTop, bottom: regionBottom, delta };
|
|
36039
36559
|
scrollHint = hint;
|
|
36040
36560
|
} else {
|
|
@@ -36334,13 +36854,13 @@ function blitEscapingAbsoluteDescendants(node, output, prevScreen, px, py, pw, p
|
|
|
36334
36854
|
}
|
|
36335
36855
|
const elem = child;
|
|
36336
36856
|
if (elem.style.position === "absolute") {
|
|
36337
|
-
const
|
|
36338
|
-
if (
|
|
36339
|
-
absoluteRectsCur.push(
|
|
36340
|
-
const cx = Math.floor(
|
|
36341
|
-
const cy = Math.floor(
|
|
36342
|
-
const cw = Math.floor(
|
|
36343
|
-
const ch = Math.floor(
|
|
36857
|
+
const cached7 = nodeCache.get(elem);
|
|
36858
|
+
if (cached7) {
|
|
36859
|
+
absoluteRectsCur.push(cached7);
|
|
36860
|
+
const cx = Math.floor(cached7.x);
|
|
36861
|
+
const cy = Math.floor(cached7.y);
|
|
36862
|
+
const cw = Math.floor(cached7.width);
|
|
36863
|
+
const ch = Math.floor(cached7.height);
|
|
36344
36864
|
if (cx < px || cy < py || cx + cw > pr || cy + ch > pb) {
|
|
36345
36865
|
output.blit(prevScreen, cx, cy, cw, ch);
|
|
36346
36866
|
}
|
|
@@ -36356,20 +36876,20 @@ function renderScrolledChildren(node, output, offsetX, offsetY, hasRemovedChild,
|
|
|
36356
36876
|
const childElem = childNode;
|
|
36357
36877
|
const cy = childElem.yogaNode;
|
|
36358
36878
|
if (cy) {
|
|
36359
|
-
const
|
|
36879
|
+
const cached7 = nodeCache.get(childElem);
|
|
36360
36880
|
let top;
|
|
36361
36881
|
let height;
|
|
36362
|
-
if (
|
|
36363
|
-
top =
|
|
36364
|
-
height =
|
|
36882
|
+
if (cached7?.top !== void 0 && !childElem.dirty && cumHeightShift === 0) {
|
|
36883
|
+
top = cached7.top;
|
|
36884
|
+
height = cached7.height;
|
|
36365
36885
|
} else {
|
|
36366
36886
|
top = cy.getComputedTop();
|
|
36367
36887
|
height = cy.getComputedHeight();
|
|
36368
36888
|
if (childElem.dirty) {
|
|
36369
|
-
cumHeightShift += height - (
|
|
36889
|
+
cumHeightShift += height - (cached7 ? cached7.height : 0);
|
|
36370
36890
|
}
|
|
36371
|
-
if (
|
|
36372
|
-
|
|
36891
|
+
if (cached7) {
|
|
36892
|
+
cached7.top = top;
|
|
36373
36893
|
}
|
|
36374
36894
|
}
|
|
36375
36895
|
const bottom = top + height;
|
|
@@ -38779,11 +39299,11 @@ var init_entry_exports = __esm({
|
|
|
38779
39299
|
return rawStringWidth(str);
|
|
38780
39300
|
}
|
|
38781
39301
|
}
|
|
38782
|
-
const
|
|
38783
|
-
if (
|
|
39302
|
+
const cached7 = widthCache.get(str);
|
|
39303
|
+
if (cached7 !== void 0) {
|
|
38784
39304
|
widthCache.delete(str);
|
|
38785
|
-
widthCache.set(str,
|
|
38786
|
-
return
|
|
39305
|
+
widthCache.set(str, cached7);
|
|
39306
|
+
return cached7;
|
|
38787
39307
|
}
|
|
38788
39308
|
const w = rawStringWidth(str);
|
|
38789
39309
|
if (widthCache.size >= WIDTH_CACHE_LIMIT) {
|
|
@@ -40888,9 +41408,9 @@ $ npm install --save-dev react-devtools-core
|
|
|
40888
41408
|
if (char.length === 1) {
|
|
40889
41409
|
const code = char.charCodeAt(0);
|
|
40890
41410
|
if (code < 128) {
|
|
40891
|
-
const
|
|
40892
|
-
if (
|
|
40893
|
-
return
|
|
41411
|
+
const cached7 = this.ascii[code];
|
|
41412
|
+
if (cached7 !== -1) {
|
|
41413
|
+
return cached7;
|
|
40894
41414
|
}
|
|
40895
41415
|
const index2 = this.strings.length;
|
|
40896
41416
|
this.strings.push(char);
|
|
@@ -45907,6 +46427,7 @@ var fmt, money, stub, eventLine, parseScheduleInput, showUsage, openjawCommands;
|
|
|
45907
46427
|
var init_openjaw = __esm({
|
|
45908
46428
|
"src/app/slash/commands/openjaw.ts"() {
|
|
45909
46429
|
"use strict";
|
|
46430
|
+
init_usage();
|
|
45910
46431
|
init_overlayStore();
|
|
45911
46432
|
fmt = /* @__PURE__ */ __name((n) => (n ?? 0).toLocaleString(), "fmt");
|
|
45912
46433
|
money = /* @__PURE__ */ __name((n) => `$${(n ?? 0).toFixed(4)}`, "money");
|
|
@@ -46154,7 +46675,7 @@ var init_openjaw = __esm({
|
|
|
46154
46675
|
if (!r.context_max) {
|
|
46155
46676
|
return ctx.transcript.sys("context usage unavailable");
|
|
46156
46677
|
}
|
|
46157
|
-
ctx.transcript.sys(`context: ${fmt(r.context_used)} / ${fmt(r.context_max)} (${r.context_percent
|
|
46678
|
+
ctx.transcript.sys(`context: ${fmt(r.context_used)} / ${fmt(r.context_max)} (${formatContextPercent(r.context_percent)})`);
|
|
46158
46679
|
}), "run")
|
|
46159
46680
|
},
|
|
46160
46681
|
{
|
|
@@ -47057,6 +47578,8 @@ var init_session2 = __esm({
|
|
|
47057
47578
|
init_slash();
|
|
47058
47579
|
init_platform();
|
|
47059
47580
|
init_text();
|
|
47581
|
+
init_theme();
|
|
47582
|
+
init_usage();
|
|
47060
47583
|
init_interfaces();
|
|
47061
47584
|
init_overlayStore();
|
|
47062
47585
|
init_uiStore();
|
|
@@ -47275,10 +47798,18 @@ var init_session2 = __esm({
|
|
|
47275
47798
|
help: "switch theme skin (fires skin.changed)",
|
|
47276
47799
|
name: "skin",
|
|
47277
47800
|
run: /* @__PURE__ */ __name((arg, ctx) => {
|
|
47278
|
-
|
|
47279
|
-
|
|
47801
|
+
const value = arg.trim().toLowerCase();
|
|
47802
|
+
if (!value || value === "list") {
|
|
47803
|
+
return ctx.transcript.panel("Skins", [
|
|
47804
|
+
{ rows: BUILTIN_SKINS.map((skin) => [skin.name, skin.description]) },
|
|
47805
|
+
{ text: "Use /skin <name> to apply a skin." }
|
|
47806
|
+
]);
|
|
47807
|
+
}
|
|
47808
|
+
if (!isBuiltinSkinName(value)) {
|
|
47809
|
+
return ctx.transcript.sys(`usage: /skin <${BUILTIN_SKINS.map((s) => s.name).join("|")}>`);
|
|
47280
47810
|
}
|
|
47281
|
-
|
|
47811
|
+
patchUiState({ theme: themeForBuiltinSkin(value) });
|
|
47812
|
+
ctx.gateway.rpc("config.set", { key: "skin", value }).then(ctx.guarded(() => ctx.transcript.sys(`skin \u2192 ${value}`)));
|
|
47282
47813
|
}, "run")
|
|
47283
47814
|
},
|
|
47284
47815
|
{
|
|
@@ -47445,7 +47976,7 @@ var init_session2 = __esm({
|
|
|
47445
47976
|
}
|
|
47446
47977
|
const sections = [{ rows }];
|
|
47447
47978
|
if (r.context_max) {
|
|
47448
|
-
sections.push({ text: `Context: ${f(r.context_used)} / ${f(r.context_max)} (${r.context_percent}
|
|
47979
|
+
sections.push({ text: `Context: ${f(r.context_used)} / ${f(r.context_max)} (${formatContextPercent(r.context_percent)})` });
|
|
47449
47980
|
}
|
|
47450
47981
|
if (r.compressions) {
|
|
47451
47982
|
sections.push({ text: `Compressions: ${r.compressions}` });
|
|
@@ -47569,6 +48100,14 @@ function buildSlashCompletions(text) {
|
|
|
47569
48100
|
if (!text.startsWith("/")) {
|
|
47570
48101
|
return { items: [], replace_from: 1 };
|
|
47571
48102
|
}
|
|
48103
|
+
const skinArgMatch = /^\/skin\s+([^\s]*)$/i.exec(text);
|
|
48104
|
+
if (skinArgMatch) {
|
|
48105
|
+
const prefix = skinArgMatch[1]?.toLowerCase() ?? "";
|
|
48106
|
+
return {
|
|
48107
|
+
items: BUILTIN_SKINS.filter((skin) => skin.name.startsWith(prefix)).map((skin) => ({ display: skin.name, meta: skin.description, text: skin.name })),
|
|
48108
|
+
replace_from: text.length - (skinArgMatch[1]?.length ?? 0)
|
|
48109
|
+
};
|
|
48110
|
+
}
|
|
47572
48111
|
const needle = text.slice(1).toLowerCase();
|
|
47573
48112
|
const seen = /* @__PURE__ */ new Set();
|
|
47574
48113
|
const items = [];
|
|
@@ -47587,6 +48126,19 @@ function buildSlashCompletions(text) {
|
|
|
47587
48126
|
});
|
|
47588
48127
|
}
|
|
47589
48128
|
}
|
|
48129
|
+
if (needle.length > 0) {
|
|
48130
|
+
for (const skill of discoverSkills()) {
|
|
48131
|
+
if (!skill.name.toLowerCase().startsWith(needle)) continue;
|
|
48132
|
+
const command = `/${skill.name}`;
|
|
48133
|
+
if (seen.has(command)) continue;
|
|
48134
|
+
seen.add(command);
|
|
48135
|
+
items.push({
|
|
48136
|
+
display: command,
|
|
48137
|
+
meta: `skill \xB7 ${skill.meta.whenToUse || skill.meta.description || ""}`,
|
|
48138
|
+
text: command
|
|
48139
|
+
});
|
|
48140
|
+
}
|
|
48141
|
+
}
|
|
47590
48142
|
items.sort((a, b) => {
|
|
47591
48143
|
const aExact = a.text.slice(1).toLowerCase() === needle ? -1 : 0;
|
|
47592
48144
|
const bExact = b.text.slice(1).toLowerCase() === needle ? -1 : 0;
|
|
@@ -47643,6 +48195,8 @@ var init_catalog = __esm({
|
|
|
47643
48195
|
init_ops();
|
|
47644
48196
|
init_session2();
|
|
47645
48197
|
init_setup();
|
|
48198
|
+
init_registry2();
|
|
48199
|
+
init_theme();
|
|
47646
48200
|
CATEGORIZED = [
|
|
47647
48201
|
{ category: "Core", commands: coreCommands },
|
|
47648
48202
|
{ category: "Session", commands: sessionCommands },
|
|
@@ -47663,7 +48217,7 @@ var init_catalog = __esm({
|
|
|
47663
48217
|
// src/rpcHandlers.ts
|
|
47664
48218
|
import { spawn as spawn7 } from "node:child_process";
|
|
47665
48219
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
47666
|
-
import { existsSync as existsSync31, mkdirSync as mkdirSync17, readFileSync as readFileSync28, rmSync, statSync as
|
|
48220
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync17, readFileSync as readFileSync28, rmSync, statSync as statSync4, writeFileSync as writeFileSync19 } from "node:fs";
|
|
47667
48221
|
import { homedir as homedir28 } from "node:os";
|
|
47668
48222
|
import { basename as basename3, extname as extname4, join as join42 } from "node:path";
|
|
47669
48223
|
function registerRpcHandlers(options) {
|
|
@@ -48356,8 +48910,7 @@ ${helpMessage}` : field.label;
|
|
|
48356
48910
|
return { cancelled: true, slug: entry.slug };
|
|
48357
48911
|
});
|
|
48358
48912
|
bus.registerRpc("commands.catalog", () => {
|
|
48359
|
-
|
|
48360
|
-
return buildCommandsCatalog({ skillCount });
|
|
48913
|
+
return buildCommandsCatalog({ skillCount: discoverSkills().length });
|
|
48361
48914
|
});
|
|
48362
48915
|
bus.registerRpc("completion.query", () => ({
|
|
48363
48916
|
items: []
|
|
@@ -48365,14 +48918,9 @@ ${helpMessage}` : field.label;
|
|
|
48365
48918
|
bus.registerRpc("complete.slash", (params) => buildSlashCompletions(String(params.text ?? "")));
|
|
48366
48919
|
bus.registerRpc("complete.path", (params) => buildPathCompletions(String(params.word ?? "")));
|
|
48367
48920
|
bus.registerRpc("skills.catalog", () => {
|
|
48368
|
-
const tools = toolRegistry.listTools();
|
|
48369
|
-
const skillTools = tools.filter((t) => /^skill[:_-]/i.test(t.name));
|
|
48370
48921
|
return {
|
|
48371
|
-
categories:
|
|
48372
|
-
skills:
|
|
48373
|
-
description: t.description,
|
|
48374
|
-
name: t.name.replace(/^skill[:_-]/i, "")
|
|
48375
|
-
}))
|
|
48922
|
+
categories: Object.keys(registrySkillsByCategory()).sort(),
|
|
48923
|
+
skills: listRegistrySkills()
|
|
48376
48924
|
};
|
|
48377
48925
|
});
|
|
48378
48926
|
bus.registerRpc("tools.list", () => ({
|
|
@@ -48404,11 +48952,11 @@ ${helpMessage}` : field.label;
|
|
|
48404
48952
|
return { output: lines.join("\n") };
|
|
48405
48953
|
}
|
|
48406
48954
|
if (head === "skills") {
|
|
48407
|
-
const skills =
|
|
48955
|
+
const skills = listRegistrySkills();
|
|
48408
48956
|
if (!skills.length) {
|
|
48409
|
-
return { output: "no skills
|
|
48957
|
+
return { output: "no skills available" };
|
|
48410
48958
|
}
|
|
48411
|
-
const lines = [`${skills.length} skills
|
|
48959
|
+
const lines = [`${skills.length} skills available`, ""];
|
|
48412
48960
|
for (const s of skills.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
48413
48961
|
const desc = s.description ? ` \u2014 ${s.description}` : "";
|
|
48414
48962
|
lines.push(` ${s.name}${desc}`);
|
|
@@ -48684,7 +49232,7 @@ ${helpMessage}` : field.label;
|
|
|
48684
49232
|
const meta = agentLoop.getSessionMeta();
|
|
48685
49233
|
const tools = toolRegistry.listTools();
|
|
48686
49234
|
const cost = `$${usage2.cost_usd.toFixed(4)}`;
|
|
48687
|
-
const ctx = usage2.context_max > 0 ? `${usage2.context_percent}
|
|
49235
|
+
const ctx = usage2.context_max > 0 ? `${formatContextPercent(usage2.context_percent)} (${usage2.context_used}/${usage2.context_max})` : "?";
|
|
48688
49236
|
const lines = [
|
|
48689
49237
|
`Session: ${meta.id}`,
|
|
48690
49238
|
`Title: ${meta.summary || "(untitled)"}`,
|
|
@@ -48814,7 +49362,7 @@ ${helpMessage}` : field.label;
|
|
|
48814
49362
|
let fileSize = 0;
|
|
48815
49363
|
try {
|
|
48816
49364
|
buffer = readFileSync28(path3);
|
|
48817
|
-
fileSize =
|
|
49365
|
+
fileSize = statSync4(path3).size;
|
|
48818
49366
|
} catch (err) {
|
|
48819
49367
|
throw new Error(`image.attach: ${err instanceof Error ? err.message : String(err)}`);
|
|
48820
49368
|
}
|
|
@@ -48909,9 +49457,9 @@ ${helpMessage}` : field.label;
|
|
|
48909
49457
|
bus.registerRpc("spawn_tree.load", () => ({ subagents: [] }));
|
|
48910
49458
|
bus.registerRpc("skills.reload", async () => {
|
|
48911
49459
|
try {
|
|
48912
|
-
|
|
48913
|
-
const skillCount =
|
|
48914
|
-
return { output: `Skills reloaded \xB7 ${skillCount} skills
|
|
49460
|
+
clearSkillsCache();
|
|
49461
|
+
const skillCount = discoverSkills().length;
|
|
49462
|
+
return { output: `Skills reloaded \xB7 ${skillCount} skills available` };
|
|
48915
49463
|
} catch (err) {
|
|
48916
49464
|
return { output: `skills reload failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
48917
49465
|
}
|
|
@@ -48919,18 +49467,28 @@ ${helpMessage}` : field.label;
|
|
|
48919
49467
|
bus.registerRpc("skills.manage", (params) => {
|
|
48920
49468
|
const action2 = String(params.action ?? "").toLowerCase();
|
|
48921
49469
|
const query = String(params.query ?? "").trim().toLowerCase();
|
|
48922
|
-
const
|
|
49470
|
+
const skills = listRegistrySkills();
|
|
48923
49471
|
if (action2 === "list") {
|
|
48924
|
-
return { skills:
|
|
49472
|
+
return { skills: registrySkillsByCategory() };
|
|
48925
49473
|
}
|
|
48926
49474
|
if (action2 === "inspect") {
|
|
48927
|
-
const hit =
|
|
49475
|
+
const hit = query ? findSkill(query) : null;
|
|
48928
49476
|
if (!hit) return { info: null };
|
|
48929
|
-
return {
|
|
49477
|
+
return {
|
|
49478
|
+
info: {
|
|
49479
|
+
category: hit.source,
|
|
49480
|
+
description: skillDescription(hit),
|
|
49481
|
+
entrypoint: hit.entrypoint,
|
|
49482
|
+
name: hit.name,
|
|
49483
|
+
path: hit.filePath,
|
|
49484
|
+
root_dir: hit.rootDir,
|
|
49485
|
+
source: hit.source
|
|
49486
|
+
}
|
|
49487
|
+
};
|
|
48930
49488
|
}
|
|
48931
49489
|
if (action2 === "search") {
|
|
48932
49490
|
if (!query) return { results: [] };
|
|
48933
|
-
const results =
|
|
49491
|
+
const results = skills.filter((s) => s.name.toLowerCase().includes(query) || (s.description ?? "").toLowerCase().includes(query)).map((s) => ({ description: s.description, name: s.name }));
|
|
48934
49492
|
return { results };
|
|
48935
49493
|
}
|
|
48936
49494
|
if (action2 === "install") {
|
|
@@ -48954,8 +49512,30 @@ ${helpMessage}` : field.label;
|
|
|
48954
49512
|
unknown: names.length ? names : [`/tools ${action2 || "?"} is not yet wired in the new TUI \u2014 use the legacy --legacy-ui flag for full toolset toggles`]
|
|
48955
49513
|
};
|
|
48956
49514
|
});
|
|
48957
|
-
bus.registerRpc("command.dispatch", (params) => {
|
|
49515
|
+
bus.registerRpc("command.dispatch", async (params) => {
|
|
48958
49516
|
const name = String(params.name ?? "").trim();
|
|
49517
|
+
const arg = String(params.arg ?? "").trim();
|
|
49518
|
+
if (name) {
|
|
49519
|
+
const skill = findSkill(name);
|
|
49520
|
+
if (skill) {
|
|
49521
|
+
if (!toolRegistry.getTool("invoke_skill")) {
|
|
49522
|
+
return { output: "skill invocation is unavailable: invoke_skill tool is not registered", type: "exec" };
|
|
49523
|
+
}
|
|
49524
|
+
try {
|
|
49525
|
+
const result = await toolRegistry.execute("invoke_skill", { skill: skill.name, args: arg });
|
|
49526
|
+
return { output: formatSkillExecutionResult(result), type: "exec" };
|
|
49527
|
+
} catch (err) {
|
|
49528
|
+
return { output: `skill failed (${skill.name}): ${err instanceof Error ? err.message : String(err)}`, type: "exec" };
|
|
49529
|
+
}
|
|
49530
|
+
}
|
|
49531
|
+
const matches = findSkillMatches(name);
|
|
49532
|
+
if (matches.length > 1) {
|
|
49533
|
+
return {
|
|
49534
|
+
output: `ambiguous skill command /${name}: ${matches.slice(0, 8).map((s) => s.name).join(", ")}${matches.length > 8 ? ", \u2026" : ""}`,
|
|
49535
|
+
type: "exec"
|
|
49536
|
+
};
|
|
49537
|
+
}
|
|
49538
|
+
}
|
|
48959
49539
|
return { output: name ? `unknown command: /${name}` : "(no command)", type: "exec" };
|
|
48960
49540
|
});
|
|
48961
49541
|
bus.registerRpc("delegation.status", () => ({ delegated: [], paused: false }));
|
|
@@ -48985,7 +49565,7 @@ ${helpMessage}` : field.label;
|
|
|
48985
49565
|
}
|
|
48986
49566
|
};
|
|
48987
49567
|
}
|
|
48988
|
-
var PROVIDERS2, PROVIDER_LABELS, PROVIDER_AUTH, isProviderAuthenticated, buildProviderOption, fetchLiveModels, parseReasoningEffortInput, reasoningEffortsForModel, resolveReasoningEffortForModel, BRIDGE_SOURCES, isBridgeSource, inferBridgeSource, bridgeLabels, bridgeEventLabels, stripBridgeGlyph, firstLogLine, bridgeUser, formatBridgeText, runProcess, contentToText, sessionMessageToMarkdown,
|
|
49568
|
+
var PROVIDERS2, PROVIDER_LABELS, PROVIDER_AUTH, isProviderAuthenticated, buildProviderOption, fetchLiveModels, parseReasoningEffortInput, skillDescription, listRegistrySkills, registrySkillsByCategory, formatSkillExecutionResult, reasoningEffortsForModel, resolveReasoningEffortForModel, BRIDGE_SOURCES, isBridgeSource, inferBridgeSource, bridgeLabels, bridgeEventLabels, stripBridgeGlyph, firstLogLine, bridgeUser, formatBridgeText, runProcess, contentToText, sessionMessageToMarkdown, sessionInfoSnapshot, MCP_TOOL_PREFIX, MAX_TOTAL_TOOLS, syncMcpTools;
|
|
48989
49569
|
var init_rpcHandlers = __esm({
|
|
48990
49570
|
"src/rpcHandlers.ts"() {
|
|
48991
49571
|
"use strict";
|
|
@@ -49004,6 +49584,10 @@ var init_rpcHandlers = __esm({
|
|
|
49004
49584
|
init_models_static();
|
|
49005
49585
|
init_providers();
|
|
49006
49586
|
init_types();
|
|
49587
|
+
init_skills();
|
|
49588
|
+
init_registry2();
|
|
49589
|
+
init_usage();
|
|
49590
|
+
init_usageSnapshot();
|
|
49007
49591
|
init_registry3();
|
|
49008
49592
|
PROVIDERS2 = ["anthropic", "openai", "github-copilot"];
|
|
49009
49593
|
PROVIDER_LABELS = {
|
|
@@ -49104,6 +49688,38 @@ var init_rpcHandlers = __esm({
|
|
|
49104
49688
|
}
|
|
49105
49689
|
return { clear: false, effort: normalized };
|
|
49106
49690
|
}, "parseReasoningEffortInput");
|
|
49691
|
+
skillDescription = /* @__PURE__ */ __name((skill) => skill.meta.whenToUse || skill.meta.description || "", "skillDescription");
|
|
49692
|
+
listRegistrySkills = /* @__PURE__ */ __name(() => discoverSkills().map((skill) => ({
|
|
49693
|
+
category: skill.source,
|
|
49694
|
+
description: skillDescription(skill),
|
|
49695
|
+
entrypoint: skill.entrypoint,
|
|
49696
|
+
name: skill.name,
|
|
49697
|
+
path: skill.filePath,
|
|
49698
|
+
root_dir: skill.rootDir,
|
|
49699
|
+
source: skill.source
|
|
49700
|
+
})), "listRegistrySkills");
|
|
49701
|
+
registrySkillsByCategory = /* @__PURE__ */ __name(() => {
|
|
49702
|
+
const grouped = {};
|
|
49703
|
+
for (const skill of discoverSkills()) {
|
|
49704
|
+
const category = skill.source;
|
|
49705
|
+
grouped[category] ??= [];
|
|
49706
|
+
grouped[category].push(skill.name);
|
|
49707
|
+
}
|
|
49708
|
+
for (const skills of Object.values(grouped)) {
|
|
49709
|
+
skills.sort((a, b) => a.localeCompare(b));
|
|
49710
|
+
}
|
|
49711
|
+
return grouped;
|
|
49712
|
+
}, "registrySkillsByCategory");
|
|
49713
|
+
formatSkillExecutionResult = /* @__PURE__ */ __name((value) => {
|
|
49714
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
49715
|
+
return typeof value === "string" ? value : JSON.stringify(value ?? null);
|
|
49716
|
+
}
|
|
49717
|
+
const result = value;
|
|
49718
|
+
if (result.success === false) {
|
|
49719
|
+
return `skill failed${result.skill ? ` (${String(result.skill)})` : ""}: ${String(result.error ?? "unknown error")}`;
|
|
49720
|
+
}
|
|
49721
|
+
return typeof result.result === "string" ? result.result : JSON.stringify(result);
|
|
49722
|
+
}, "formatSkillExecutionResult");
|
|
49107
49723
|
reasoningEffortsForModel = /* @__PURE__ */ __name((model) => model?.supportedReasoningEfforts?.map((option) => option.effort) ?? [], "reasoningEffortsForModel");
|
|
49108
49724
|
resolveReasoningEffortForModel = /* @__PURE__ */ __name((model, requested) => {
|
|
49109
49725
|
const supported = reasoningEffortsForModel(model);
|
|
@@ -49207,25 +49823,6 @@ ${raw}`;
|
|
|
49207
49823
|
}
|
|
49208
49824
|
return [];
|
|
49209
49825
|
}, "sessionMessageToMarkdown");
|
|
49210
|
-
usageSnapshot = /* @__PURE__ */ __name((agentLoop) => {
|
|
49211
|
-
const cost = agentLoop.costTracker.getSessionCost();
|
|
49212
|
-
const contextMax = agentLoop.contextManager.getContextWindow(agentLoop.model);
|
|
49213
|
-
const contextUsed = agentLoop.contextManager.lastPromptTokens;
|
|
49214
|
-
return {
|
|
49215
|
-
cache_read: cost.totalCacheReadTokens,
|
|
49216
|
-
cache_write: cost.totalCacheCreationTokens,
|
|
49217
|
-
calls: cost.turns,
|
|
49218
|
-
context_max: contextMax,
|
|
49219
|
-
context_percent: contextMax > 0 ? Math.round(contextUsed / contextMax * 100) : 0,
|
|
49220
|
-
context_used: contextUsed,
|
|
49221
|
-
cost_status: "estimated",
|
|
49222
|
-
cost_usd: cost.totalCostUSD,
|
|
49223
|
-
input: cost.totalInputTokens,
|
|
49224
|
-
model: agentLoop.model,
|
|
49225
|
-
output: cost.totalOutputTokens,
|
|
49226
|
-
total: cost.totalInputTokens + cost.totalOutputTokens + cost.totalCacheReadTokens + cost.totalCacheCreationTokens
|
|
49227
|
-
};
|
|
49228
|
-
}, "usageSnapshot");
|
|
49229
49826
|
sessionInfoSnapshot = /* @__PURE__ */ __name((agentLoop, toolRegistry) => ({
|
|
49230
49827
|
cwd: process.cwd(),
|
|
49231
49828
|
model: agentLoop.model,
|
|
@@ -49483,7 +50080,7 @@ var init_gatewayContext = __esm({
|
|
|
49483
50080
|
});
|
|
49484
50081
|
|
|
49485
50082
|
// src/domain/paths.ts
|
|
49486
|
-
var shortCwd,
|
|
50083
|
+
var shortCwd, fullCwdBranch;
|
|
49487
50084
|
var init_paths = __esm({
|
|
49488
50085
|
"src/domain/paths.ts"() {
|
|
49489
50086
|
"use strict";
|
|
@@ -49492,13 +50089,7 @@ var init_paths = __esm({
|
|
|
49492
50089
|
const p = h && cwd.startsWith(h) ? `~${cwd.slice(h.length)}` : cwd;
|
|
49493
50090
|
return p.length <= max ? p : `\u2026${p.slice(-(max - 1))}`;
|
|
49494
50091
|
}, "shortCwd");
|
|
49495
|
-
|
|
49496
|
-
if (!branch) {
|
|
49497
|
-
return shortCwd(cwd, max);
|
|
49498
|
-
}
|
|
49499
|
-
const tag = ` (${branch.length > 16 ? `\u2026${branch.slice(-15)}` : branch})`;
|
|
49500
|
-
return `${shortCwd(cwd, Math.max(8, max - tag.length))}${tag}`;
|
|
49501
|
-
}, "fmtCwdBranch");
|
|
50092
|
+
fullCwdBranch = /* @__PURE__ */ __name((cwd, branch) => branch ? `${cwd} (${branch})` : cwd, "fullCwdBranch");
|
|
49502
50093
|
}
|
|
49503
50094
|
});
|
|
49504
50095
|
|
|
@@ -49866,9 +50457,9 @@ var init_useVirtualHistory = __esm({
|
|
|
49866
50457
|
viewportHeight
|
|
49867
50458
|
}) => itemCount > 0 && viewportHeight > 0 && !sticky && !liveTailActive, "shouldSetVirtualClamp");
|
|
49868
50459
|
ensureVirtualItemHeight = /* @__PURE__ */ __name((heights, key, index, estimate, estimateHeight) => {
|
|
49869
|
-
const
|
|
49870
|
-
if (
|
|
49871
|
-
return Math.max(1, Math.floor(
|
|
50460
|
+
const cached7 = heights.get(key);
|
|
50461
|
+
if (cached7 !== void 0) {
|
|
50462
|
+
return Math.max(1, Math.floor(cached7));
|
|
49872
50463
|
}
|
|
49873
50464
|
const seeded = Math.max(1, Math.floor(estimateHeight?.(index, key) ?? estimate));
|
|
49874
50465
|
heights.set(key, seeded);
|
|
@@ -51800,7 +52391,7 @@ function createSlashHandler(ctx) {
|
|
|
51800
52391
|
}
|
|
51801
52392
|
}
|
|
51802
52393
|
}
|
|
51803
|
-
|
|
52394
|
+
const renderSlashExec = /* @__PURE__ */ __name((r) => {
|
|
51804
52395
|
if (stale()) {
|
|
51805
52396
|
return;
|
|
51806
52397
|
}
|
|
@@ -51809,33 +52400,41 @@ function createSlashHandler(ctx) {
|
|
|
51809
52400
|
${body}` : body;
|
|
51810
52401
|
const long = text.length > 180 || text.split("\n").filter(Boolean).length > 2;
|
|
51811
52402
|
long ? page(text, parsed.name[0].toUpperCase() + parsed.name.slice(1)) : sys(text);
|
|
51812
|
-
})
|
|
51813
|
-
|
|
51814
|
-
|
|
51815
|
-
|
|
51816
|
-
|
|
51817
|
-
|
|
51818
|
-
|
|
51819
|
-
|
|
51820
|
-
|
|
51821
|
-
|
|
51822
|
-
|
|
51823
|
-
|
|
51824
|
-
|
|
51825
|
-
|
|
51826
|
-
|
|
51827
|
-
|
|
52403
|
+
}, "renderSlashExec");
|
|
52404
|
+
const runSlashExec = /* @__PURE__ */ __name(() => {
|
|
52405
|
+
gw.request("slash.exec", { command: cmd.slice(1), session_id: sid }).then(renderSlashExec).catch(guardedErr);
|
|
52406
|
+
}, "runSlashExec");
|
|
52407
|
+
const skillHint = findSkill(parsed.name);
|
|
52408
|
+
if (skillHint) {
|
|
52409
|
+
sys(`\u26A1 loading skill: ${skillHint.name}`);
|
|
52410
|
+
}
|
|
52411
|
+
gw.request("command.dispatch", { arg: parsed.arg, name: parsed.name, session_id: sid }).then((raw) => {
|
|
52412
|
+
if (stale()) {
|
|
52413
|
+
return;
|
|
52414
|
+
}
|
|
52415
|
+
const d = asCommandDispatch(raw);
|
|
52416
|
+
if (!d) {
|
|
52417
|
+
return runSlashExec();
|
|
52418
|
+
}
|
|
52419
|
+
if (d.type === "exec" || d.type === "plugin") {
|
|
52420
|
+
return sys(d.output || "(no output)");
|
|
52421
|
+
}
|
|
52422
|
+
if (d.type === "alias") {
|
|
52423
|
+
return handler(`/${d.target}${argTail}`);
|
|
52424
|
+
}
|
|
52425
|
+
if (d.type === "skill") {
|
|
52426
|
+
if (!skillHint || skillHint.name !== d.name) {
|
|
51828
52427
|
sys(`\u26A1 loading skill: ${d.name}`);
|
|
51829
|
-
return d.message?.trim() ? send(d.message) : sys(`/${parsed.name}: skill payload missing message`);
|
|
51830
52428
|
}
|
|
51831
|
-
|
|
51832
|
-
|
|
51833
|
-
|
|
51834
|
-
|
|
51835
|
-
|
|
52429
|
+
return d.message?.trim() ? send(d.message) : sys(`/${parsed.name}: skill payload missing message`);
|
|
52430
|
+
}
|
|
52431
|
+
if (d.type === "send") {
|
|
52432
|
+
if (d.notice?.trim()) {
|
|
52433
|
+
sys(d.notice);
|
|
51836
52434
|
}
|
|
51837
|
-
|
|
51838
|
-
|
|
52435
|
+
return d.message?.trim() ? send(d.message) : sys(`/${parsed.name}: empty message`);
|
|
52436
|
+
}
|
|
52437
|
+
}).catch(runSlashExec);
|
|
51839
52438
|
return true;
|
|
51840
52439
|
}, "handler");
|
|
51841
52440
|
return handler;
|
|
@@ -51845,6 +52444,7 @@ var init_createSlashHandler = __esm({
|
|
|
51845
52444
|
"use strict";
|
|
51846
52445
|
init_slash();
|
|
51847
52446
|
init_rpc();
|
|
52447
|
+
init_registry2();
|
|
51848
52448
|
init_registry4();
|
|
51849
52449
|
init_uiStore();
|
|
51850
52450
|
__name(createSlashHandler, "createSlashHandler");
|
|
@@ -53462,6 +54062,13 @@ var init_paste = __esm({
|
|
|
53462
54062
|
|
|
53463
54063
|
// src/app/useSubmission.ts
|
|
53464
54064
|
import { useCallback as useCallback9, useEffect as useEffect11, useRef as useRef12 } from "react";
|
|
54065
|
+
function resolveCompletionSubmit(value, row, replaceFrom) {
|
|
54066
|
+
if (!row?.text) return null;
|
|
54067
|
+
const text = value.startsWith("/") && row.text.startsWith("/") ? row.text.slice(1) : row.text;
|
|
54068
|
+
const next = value.slice(0, replaceFrom) + text;
|
|
54069
|
+
if (next === value) return null;
|
|
54070
|
+
return { next, submit: value.startsWith("/") && row.text.startsWith("/") && row.meta?.startsWith("skill \xB7") === true };
|
|
54071
|
+
}
|
|
53465
54072
|
function useSubmission(opts) {
|
|
53466
54073
|
const {
|
|
53467
54074
|
appendMessage,
|
|
@@ -53686,12 +54293,9 @@ function useSubmission(opts) {
|
|
|
53686
54293
|
(value) => {
|
|
53687
54294
|
if (composerState.completions.length) {
|
|
53688
54295
|
const row = composerState.completions[composerState.compIdx];
|
|
53689
|
-
|
|
53690
|
-
|
|
53691
|
-
|
|
53692
|
-
if (next !== value) {
|
|
53693
|
-
return composerActions.setInput(next);
|
|
53694
|
-
}
|
|
54296
|
+
const completion = resolveCompletionSubmit(value, row, composerState.compReplace);
|
|
54297
|
+
if (completion) {
|
|
54298
|
+
return completion.submit ? dispatchSubmission(completion.next) : composerActions.setInput(completion.next);
|
|
53695
54299
|
}
|
|
53696
54300
|
}
|
|
53697
54301
|
if (!value.trim() && !composerState.inputBuf.length) {
|
|
@@ -53748,6 +54352,7 @@ var init_useSubmission = __esm({
|
|
|
53748
54352
|
return (value) => value.replace(PASTE_SNIPPET_RE, (tok) => byLabel.get(tok)?.shift() ?? tok);
|
|
53749
54353
|
}, "expandSnips");
|
|
53750
54354
|
spliceMatches = /* @__PURE__ */ __name((text, matches, results) => matches.reduceRight((acc, m, i) => acc.slice(0, m.index) + results[i] + acc.slice(m.index + m[0].length), text), "spliceMatches");
|
|
54355
|
+
__name(resolveCompletionSubmit, "resolveCompletionSubmit");
|
|
53751
54356
|
__name(useSubmission, "useSubmission");
|
|
53752
54357
|
}
|
|
53753
54358
|
});
|
|
@@ -54332,7 +54937,7 @@ function useMainApp(gw) {
|
|
|
54332
54937
|
const gitBranch = useGitBranch(cwd);
|
|
54333
54938
|
const appStatus = useMemo7(
|
|
54334
54939
|
() => ({
|
|
54335
|
-
cwdLabel:
|
|
54940
|
+
cwdLabel: fullCwdBranch(cwd, gitBranch),
|
|
54336
54941
|
goodVibesTick,
|
|
54337
54942
|
sessionStartedAt: ui.sid ? sessionStartedAt : null,
|
|
54338
54943
|
showStickyPrompt: !!stickyPrompt,
|
|
@@ -55402,7 +56007,7 @@ import { useStore as useStore5 } from "@nanostores/react";
|
|
|
55402
56007
|
import { useEffect as useEffect14, useMemo as useMemo10, useRef as useRef15, useState as useState15 } from "react";
|
|
55403
56008
|
import unicodeSpinners from "unicode-animations";
|
|
55404
56009
|
import { Fragment as Fragment4, jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
55405
|
-
function
|
|
56010
|
+
function useTickerText(startedAt) {
|
|
55406
56011
|
const ui = useStore5($uiState);
|
|
55407
56012
|
const style = ui.indicatorStyle;
|
|
55408
56013
|
const [tick, setTick] = useState15(() => Math.floor(Math.random() * 1e3));
|
|
@@ -55425,11 +56030,7 @@ function FaceTicker({ color, startedAt }) {
|
|
|
55425
56030
|
const verb = VERBS[verbTick % VERBS.length] ?? "";
|
|
55426
56031
|
const verbSegment = showVerb ? ` ${padVerb(verb)}` : "";
|
|
55427
56032
|
const durationSegment = startedAt ? ` \xB7 ${fmtDuration(now2 - startedAt)}` : "";
|
|
55428
|
-
return
|
|
55429
|
-
frame,
|
|
55430
|
-
verbSegment,
|
|
55431
|
-
durationSegment
|
|
55432
|
-
] });
|
|
56033
|
+
return `${frame}${verbSegment}${durationSegment}`;
|
|
55433
56034
|
}
|
|
55434
56035
|
function ctxBarColor(pct, t) {
|
|
55435
56036
|
if (pct == null) {
|
|
@@ -55451,6 +56052,27 @@ function ctxBar(pct, w = 10) {
|
|
|
55451
56052
|
const filled = Math.round(p / 100 * w);
|
|
55452
56053
|
return "\u2588".repeat(filled) + "\u2591".repeat(w - filled);
|
|
55453
56054
|
}
|
|
56055
|
+
function fitVisible(text, width) {
|
|
56056
|
+
if (width <= 0) return "";
|
|
56057
|
+
if (stringWidth(text) <= width) return text + " ".repeat(width - stringWidth(text));
|
|
56058
|
+
let out = "";
|
|
56059
|
+
for (const ch of Array.from(text)) {
|
|
56060
|
+
if (stringWidth(out + ch + "\u2026") > width) break;
|
|
56061
|
+
out += ch;
|
|
56062
|
+
}
|
|
56063
|
+
return out + "\u2026" + " ".repeat(Math.max(0, width - stringWidth(out + "\u2026")));
|
|
56064
|
+
}
|
|
56065
|
+
function truncateTailVisible(text, width) {
|
|
56066
|
+
return fitVisible(text, width);
|
|
56067
|
+
}
|
|
56068
|
+
function cwdBranchWidth(cols) {
|
|
56069
|
+
const desired = Math.max(18, Math.floor(cols * 0.38));
|
|
56070
|
+
const maxByCols = Math.max(6, cols - 24);
|
|
56071
|
+
return Math.max(6, Math.min(64, desired, maxByCols));
|
|
56072
|
+
}
|
|
56073
|
+
function buildActivityText(status, width) {
|
|
56074
|
+
return fitVisible(` ${status}`, width);
|
|
56075
|
+
}
|
|
55454
56076
|
function SpawnHud({ t }) {
|
|
55455
56077
|
const delegation = useStore5($delegationState);
|
|
55456
56078
|
const subagents = useTurnSelector((state) => state.subagents);
|
|
@@ -55515,12 +56137,14 @@ function GoodVibesHeart({ tick, t }) {
|
|
|
55515
56137
|
}
|
|
55516
56138
|
return /* @__PURE__ */ jsx19(Text9, { color, children: "\u2665" });
|
|
55517
56139
|
}
|
|
56140
|
+
function ActivityStatusLine({ busy, cols, status, statusColor: statusColor2, turnStartedAt }) {
|
|
56141
|
+
const tickerStatus = useTickerText(busy ? turnStartedAt : null);
|
|
56142
|
+
const text = buildActivityText(busy ? tickerStatus : status, cols);
|
|
56143
|
+
return /* @__PURE__ */ jsx19(Box_default, { height: 1, width: cols, children: /* @__PURE__ */ jsx19(Text9, { color: statusColor2, children: text }) });
|
|
56144
|
+
}
|
|
55518
56145
|
function StatusRule({
|
|
55519
56146
|
cwdLabel,
|
|
55520
56147
|
cols,
|
|
55521
|
-
busy,
|
|
55522
|
-
status,
|
|
55523
|
-
statusColor: statusColor2,
|
|
55524
56148
|
model,
|
|
55525
56149
|
modelFast,
|
|
55526
56150
|
modelReasoningEffort,
|
|
@@ -55528,7 +56152,6 @@ function StatusRule({
|
|
|
55528
56152
|
bgCount,
|
|
55529
56153
|
sessionStartedAt,
|
|
55530
56154
|
showCost,
|
|
55531
|
-
turnStartedAt,
|
|
55532
56155
|
voiceLabel,
|
|
55533
56156
|
t
|
|
55534
56157
|
}) {
|
|
@@ -55536,29 +56159,15 @@ function StatusRule({
|
|
|
55536
56159
|
const barColor = ctxBarColor(pct, t);
|
|
55537
56160
|
const ctxLabel = usage2.context_max ? `${fmtK(usage2.context_used ?? 0)}/${fmtK(usage2.context_max)}` : usage2.total > 0 ? `${fmtK(usage2.total)} tok` : "";
|
|
55538
56161
|
const bar = usage2.context_max ? ctxBar(pct) : "";
|
|
55539
|
-
const
|
|
55540
|
-
|
|
55541
|
-
|
|
55542
|
-
|
|
55543
|
-
|
|
55544
|
-
|
|
55545
|
-
|
|
55546
|
-
|
|
55547
|
-
|
|
55548
|
-
ctxLabel ? /* @__PURE__ */ jsxs10(Text9, { color: t.color.systemNote, children: [
|
|
55549
|
-
" \u2502 ",
|
|
55550
|
-
ctxLabel
|
|
55551
|
-
] }) : null,
|
|
55552
|
-
bar ? /* @__PURE__ */ jsxs10(Text9, { color: t.color.systemNote, children: [
|
|
55553
|
-
" \u2502 ",
|
|
55554
|
-
/* @__PURE__ */ jsxs10(Text9, { color: barColor, children: [
|
|
55555
|
-
"[",
|
|
55556
|
-
bar,
|
|
55557
|
-
"]"
|
|
55558
|
-
] }),
|
|
55559
|
-
" ",
|
|
55560
|
-
/* @__PURE__ */ jsx19(Text9, { color: barColor, children: pct != null ? `${pct}%` : "" })
|
|
55561
|
-
] }) : null,
|
|
56162
|
+
const cwdWidth = cwdBranchWidth(cols);
|
|
56163
|
+
const modelText = modelLabel(model, modelReasoningEffort, modelFast);
|
|
56164
|
+
return /* @__PURE__ */ jsxs10(Box_default, { height: 1, width: cols, children: [
|
|
56165
|
+
/* @__PURE__ */ jsx19(Text9, { color: t.color.border, children: "\u2500 " }),
|
|
56166
|
+
/* @__PURE__ */ jsx19(Box_default, { flexShrink: 0, width: cwdWidth, children: /* @__PURE__ */ jsx19(Text9, { color: t.color.systemNote, children: truncateTailVisible(cwdLabel, cwdWidth) }) }),
|
|
56167
|
+
/* @__PURE__ */ jsx19(Box_default, { flexShrink: 1, children: /* @__PURE__ */ jsxs10(Text9, { color: t.color.systemNote, wrap: "truncate-end", children: [
|
|
56168
|
+
modelText ? ` \u2502 ${modelText}` : "",
|
|
56169
|
+
ctxLabel ? ` \u2502 ${ctxLabel}` : "",
|
|
56170
|
+
bar ? /* @__PURE__ */ jsx19(Text9, { color: barColor, children: statusContextMeter(bar, pct) }) : null,
|
|
55562
56171
|
sessionStartedAt ? /* @__PURE__ */ jsxs10(Text9, { color: t.color.systemNote, children: [
|
|
55563
56172
|
" \u2502 ",
|
|
55564
56173
|
/* @__PURE__ */ jsx19(SessionDuration, { startedAt: sessionStartedAt })
|
|
@@ -55590,9 +56199,7 @@ function StatusRule({
|
|
|
55590
56199
|
" \u2502 $",
|
|
55591
56200
|
usage2.cost_usd.toFixed(4)
|
|
55592
56201
|
] }) : null
|
|
55593
|
-
] }) })
|
|
55594
|
-
/* @__PURE__ */ jsx19(Text9, { color: t.color.border, children: " \u2500 " }),
|
|
55595
|
-
/* @__PURE__ */ jsx19(Text9, { color: t.color.systemNote, children: cwdLabel })
|
|
56202
|
+
] }) })
|
|
55596
56203
|
] });
|
|
55597
56204
|
}
|
|
55598
56205
|
function FloatBox({ children, color }) {
|
|
@@ -55667,7 +56274,7 @@ function TranscriptScrollbar({ focused = false, scrollRef, t }) {
|
|
|
55667
56274
|
}
|
|
55668
56275
|
);
|
|
55669
56276
|
}
|
|
55670
|
-
var FACE_TICK_MS, VERB_PAD_LEN, padVerb, EMOJI_FRAMES, ASCII_FRAMES, SPINNER_TICK_MS, renderIndicator, effortLabel, shortModelLabel, modelLabel;
|
|
56277
|
+
var FACE_TICK_MS, VERB_PAD_LEN, padVerb, EMOJI_FRAMES, ASCII_FRAMES, SPINNER_TICK_MS, renderIndicator, statusContextPercent, statusContextMeter, effortLabel, shortModelLabel, modelLabel;
|
|
55671
56278
|
var init_appChrome = __esm({
|
|
55672
56279
|
"src/components/appChrome.tsx"() {
|
|
55673
56280
|
"use strict";
|
|
@@ -55678,6 +56285,7 @@ var init_appChrome = __esm({
|
|
|
55678
56285
|
init_faces();
|
|
55679
56286
|
init_verbs();
|
|
55680
56287
|
init_messages();
|
|
56288
|
+
init_usage();
|
|
55681
56289
|
init_viewport();
|
|
55682
56290
|
init_subagentTree();
|
|
55683
56291
|
init_text();
|
|
@@ -55710,9 +56318,15 @@ var init_appChrome = __esm({
|
|
|
55710
56318
|
const frame = spinner.frames[tick % spinner.frames.length] ?? "\u280B";
|
|
55711
56319
|
return { frame, intervalMs: Math.max(SPINNER_TICK_MS, spinner.interval), showVerb: false };
|
|
55712
56320
|
}, "renderIndicator");
|
|
55713
|
-
__name(
|
|
56321
|
+
__name(useTickerText, "useTickerText");
|
|
55714
56322
|
__name(ctxBarColor, "ctxBarColor");
|
|
55715
56323
|
__name(ctxBar, "ctxBar");
|
|
56324
|
+
statusContextPercent = /* @__PURE__ */ __name((pct) => formatContextPercent(pct).padStart(5), "statusContextPercent");
|
|
56325
|
+
statusContextMeter = /* @__PURE__ */ __name((bar, pct) => ` \u2502 [${bar}] ${statusContextPercent(pct)}`, "statusContextMeter");
|
|
56326
|
+
__name(fitVisible, "fitVisible");
|
|
56327
|
+
__name(truncateTailVisible, "truncateTailVisible");
|
|
56328
|
+
__name(cwdBranchWidth, "cwdBranchWidth");
|
|
56329
|
+
__name(buildActivityText, "buildActivityText");
|
|
55716
56330
|
__name(SpawnHud, "SpawnHud");
|
|
55717
56331
|
__name(SessionDuration, "SessionDuration");
|
|
55718
56332
|
effortLabel = /* @__PURE__ */ __name((effort) => {
|
|
@@ -55722,6 +56336,7 @@ var init_appChrome = __esm({
|
|
|
55722
56336
|
shortModelLabel = /* @__PURE__ */ __name((model) => model.split("/").pop().replace(/^claude[-_]/, "").replace(/^anthropic[-_]/, "").replace(/[-_]/g, " ").replace(/\b(\d+)\s+(\d+)\b/g, "$1.$2").trim(), "shortModelLabel");
|
|
55723
56337
|
modelLabel = /* @__PURE__ */ __name((model, effort, fast) => [shortModelLabel(model), effortLabel(effort), fast ? "fast" : ""].filter(Boolean).join(" "), "modelLabel");
|
|
55724
56338
|
__name(GoodVibesHeart, "GoodVibesHeart");
|
|
56339
|
+
__name(ActivityStatusLine, "ActivityStatusLine");
|
|
55725
56340
|
__name(StatusRule, "StatusRule");
|
|
55726
56341
|
__name(FloatBox, "FloatBox");
|
|
55727
56342
|
__name(StickyPromptTracker, "StickyPromptTracker");
|
|
@@ -59890,9 +60505,9 @@ function MdImpl({ compact, t, text }) {
|
|
|
59890
60505
|
const nodes = useMemo14(() => {
|
|
59891
60506
|
const bucket = cacheBucket(t);
|
|
59892
60507
|
const cacheKey = `${compact ? "1" : "0"}|${text}`;
|
|
59893
|
-
const
|
|
59894
|
-
if (
|
|
59895
|
-
return
|
|
60508
|
+
const cached7 = cacheGet(bucket, cacheKey);
|
|
60509
|
+
if (cached7) {
|
|
60510
|
+
return cached7;
|
|
59896
60511
|
}
|
|
59897
60512
|
const lines = ensureEmojiPresentation(text).split("\n");
|
|
59898
60513
|
const nodes2 = [];
|
|
@@ -61928,26 +62543,34 @@ var init_appLayout = __esm({
|
|
|
61928
62543
|
if (ui.statusBar !== at) {
|
|
61929
62544
|
return null;
|
|
61930
62545
|
}
|
|
61931
|
-
return /* @__PURE__ */
|
|
61932
|
-
|
|
61933
|
-
|
|
61934
|
-
|
|
61935
|
-
|
|
61936
|
-
|
|
61937
|
-
|
|
61938
|
-
|
|
61939
|
-
|
|
61940
|
-
|
|
61941
|
-
|
|
61942
|
-
|
|
61943
|
-
|
|
61944
|
-
|
|
61945
|
-
|
|
61946
|
-
|
|
61947
|
-
|
|
61948
|
-
|
|
61949
|
-
|
|
61950
|
-
|
|
62546
|
+
return /* @__PURE__ */ jsxs28(Box_default, { flexDirection: "column", marginTop: at === "top" ? 1 : 0, children: [
|
|
62547
|
+
/* @__PURE__ */ jsx41(
|
|
62548
|
+
ActivityStatusLine,
|
|
62549
|
+
{
|
|
62550
|
+
busy: ui.busy,
|
|
62551
|
+
cols: composer.cols,
|
|
62552
|
+
status: ui.status,
|
|
62553
|
+
statusColor: status.statusColor,
|
|
62554
|
+
turnStartedAt: status.turnStartedAt
|
|
62555
|
+
}
|
|
62556
|
+
),
|
|
62557
|
+
/* @__PURE__ */ jsx41(
|
|
62558
|
+
StatusRule,
|
|
62559
|
+
{
|
|
62560
|
+
bgCount: ui.bgTasks.size,
|
|
62561
|
+
cols: composer.cols,
|
|
62562
|
+
cwdLabel: status.cwdLabel,
|
|
62563
|
+
model: ui.info?.model ?? "",
|
|
62564
|
+
modelFast: ui.info?.fast || ui.info?.service_tier === "priority",
|
|
62565
|
+
modelReasoningEffort: ui.info?.reasoning_effort,
|
|
62566
|
+
sessionStartedAt: status.sessionStartedAt,
|
|
62567
|
+
showCost: ui.showCost,
|
|
62568
|
+
t: ui.theme,
|
|
62569
|
+
usage: ui.usage,
|
|
62570
|
+
voiceLabel: status.voiceLabel
|
|
62571
|
+
}
|
|
62572
|
+
)
|
|
62573
|
+
] });
|
|
61951
62574
|
}, "StatusRulePane"));
|
|
61952
62575
|
AppLayout = memo7(/* @__PURE__ */ __name(function AppLayout2({
|
|
61953
62576
|
actions,
|