@getpaseo/server 0.1.97-beta.3 → 0.1.98
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/dist/server/server/agent/agent-manager.d.ts +11 -3
- package/dist/server/server/agent/agent-manager.js +95 -23
- package/dist/server/server/agent/agent-prompt.d.ts +1 -1
- package/dist/server/server/agent/agent-prompt.js +3 -10
- package/dist/server/server/agent/agent-response-loop.js +9 -3
- package/dist/server/server/agent/agent-sdk-types.d.ts +9 -3
- package/dist/server/server/agent/agent-storage.d.ts +20 -240
- package/dist/server/server/agent/agent-storage.js +6 -6
- package/dist/server/server/agent/create-agent/create.d.ts +2 -0
- package/dist/server/server/agent/create-agent/create.js +8 -7
- package/dist/server/server/agent/lifecycle-command.d.ts +15 -1
- package/dist/server/server/agent/lifecycle-command.js +9 -2
- package/dist/server/server/agent/mcp-server.js +263 -119
- package/dist/server/server/agent/mcp-shared.d.ts +35 -179
- package/dist/server/server/agent/provider-notices.d.ts +3 -0
- package/dist/server/server/agent/provider-notices.js +5 -0
- package/dist/server/server/agent/provider-registry.d.ts +2 -0
- package/dist/server/server/agent/provider-registry.js +10 -3
- package/dist/server/server/agent/provider-snapshot-manager.d.ts +3 -0
- package/dist/server/server/agent/provider-snapshot-manager.js +11 -2
- package/dist/server/server/agent/providers/claude/agent.js +257 -143
- package/dist/server/server/agent/providers/claude/models.js +7 -3
- package/dist/server/server/agent/providers/claude/project-dir.js +9 -6
- package/dist/server/server/agent/providers/claude/task-notification-tool-call.d.ts +2 -22
- package/dist/server/server/agent/providers/codex/app-server-transport.d.ts +8 -118
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +4 -3
- package/dist/server/server/agent/providers/codex-app-server-agent.js +43 -1
- package/dist/server/server/agent/providers/copilot-acp-agent.js +4 -1
- package/dist/server/server/agent/providers/diagnostic-utils.d.ts +9 -0
- package/dist/server/server/agent/providers/diagnostic-utils.js +188 -0
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +1 -5
- package/dist/server/server/agent/providers/mock-slow-provider.js +1 -1
- package/dist/server/server/agent/providers/opencode/server-manager.d.ts +29 -2
- package/dist/server/server/agent/providers/opencode/server-manager.js +83 -17
- package/dist/server/server/agent/providers/opencode-agent.d.ts +2 -0
- package/dist/server/server/agent/providers/opencode-agent.js +14 -9
- package/dist/server/server/agent/providers/pi/agent.d.ts +1 -5
- package/dist/server/server/agent/providers/pi/agent.js +27 -14
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +391 -1261
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +26 -16
- package/dist/server/server/bootstrap.d.ts +2 -0
- package/dist/server/server/bootstrap.js +32 -2
- package/dist/server/server/loop-service.d.ts +60 -359
- package/dist/server/server/managed-processes/managed-processes.d.ts +76 -0
- package/dist/server/server/managed-processes/managed-processes.js +326 -0
- package/dist/server/server/migrations/backfill-workspace-id.migration.js +10 -6
- package/dist/server/server/package-version.d.ts +1 -7
- package/dist/server/server/paseo-worktree-service.js +15 -1
- package/dist/server/server/persisted-config.d.ts +138 -1009
- package/dist/server/server/persisted-config.js +1 -1
- package/dist/server/server/pid-lock.d.ts +1 -15
- package/dist/server/server/resolve-worktree-creation-intent.d.ts +3 -0
- package/dist/server/server/resolve-worktree-creation-intent.js +3 -3
- package/dist/server/server/session.d.ts +18 -1
- package/dist/server/server/session.js +424 -64
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts +2 -2
- package/dist/server/server/speech/providers/openai/runtime.js +3 -4
- package/dist/server/server/speech/speech-types.d.ts +9 -11
- package/dist/server/server/websocket-server.d.ts +1 -0
- package/dist/server/server/websocket-server.js +15 -0
- package/dist/server/server/workspace-archive-service.js +2 -3
- package/dist/server/server/workspace-directory.js +5 -5
- package/dist/server/server/workspace-reconciliation-service.js +2 -2
- package/dist/server/server/workspace-registry.d.ts +17 -48
- package/dist/server/server/workspace-registry.js +9 -0
- package/dist/server/server/worktree-core.d.ts +1 -0
- package/dist/server/server/worktree-core.js +5 -1
- package/dist/server/services/quota-fetcher/manifest.d.ts +4 -0
- package/dist/server/services/quota-fetcher/manifest.js +47 -0
- package/dist/server/services/quota-fetcher/provider.d.ts +17 -0
- package/dist/server/services/quota-fetcher/provider.js +2 -0
- package/dist/server/services/quota-fetcher/providers/claude.d.ts +26 -0
- package/dist/server/services/quota-fetcher/providers/claude.js +217 -0
- package/dist/server/services/quota-fetcher/providers/codex.d.ts +23 -0
- package/dist/server/services/quota-fetcher/providers/codex.js +211 -0
- package/dist/server/services/quota-fetcher/providers/copilot.d.ts +17 -0
- package/dist/server/services/quota-fetcher/providers/copilot.js +75 -0
- package/dist/server/services/quota-fetcher/providers/cursor.d.ts +17 -0
- package/dist/server/services/quota-fetcher/providers/cursor.js +123 -0
- package/dist/server/services/quota-fetcher/providers/grok.d.ts +18 -0
- package/dist/server/services/quota-fetcher/providers/grok.js +89 -0
- package/dist/server/services/quota-fetcher/providers/kimi.d.ts +20 -0
- package/dist/server/services/quota-fetcher/providers/kimi.js +89 -0
- package/dist/server/services/quota-fetcher/providers/zai.d.ts +17 -0
- package/dist/server/services/quota-fetcher/providers/zai.js +58 -0
- package/dist/server/services/quota-fetcher/service.d.ts +28 -0
- package/dist/server/services/quota-fetcher/service.js +58 -0
- package/dist/server/services/quota-fetcher/usage.d.ts +22 -0
- package/dist/server/services/quota-fetcher/usage.js +49 -0
- package/dist/server/terminal/terminal-session-controller.d.ts +8 -0
- package/dist/server/terminal/terminal-session-controller.js +23 -3
- package/dist/server/utils/checkout-git.js +36 -76
- package/dist/server/utils/directory-suggestions.js +98 -2
- package/dist/server/utils/worktree-metadata.d.ts +7 -59
- package/dist/src/server/persisted-config.js +1 -1
- package/package.json +9 -9
|
@@ -9,13 +9,14 @@ import { getClaudeModelsWithSettings, normalizeClaudeRuntimeModelId } from "./mo
|
|
|
9
9
|
import { parsePartialJsonObject } from "./partial-json.js";
|
|
10
10
|
import { ClaudeSidechainTracker } from "./sidechain-tracker.js";
|
|
11
11
|
import { buildClaudeFeatures, claudeModelSupportsFastMode } from "./feature-definitions.js";
|
|
12
|
-
import { buildBinaryDiagnosticRows, formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, toDiagnosticErrorMessage, } from "../diagnostic-utils.js";
|
|
12
|
+
import { buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, toDiagnosticErrorMessage, } from "../diagnostic-utils.js";
|
|
13
13
|
import { appendOrReplaceGrowingAssistantMessage, runProviderTurn } from "../provider-runner.js";
|
|
14
14
|
import { renderPromptAttachmentAsText } from "../../prompt-attachments.js";
|
|
15
15
|
import { claudeQuery } from "./query.js";
|
|
16
16
|
import { realClaudeRewindSdk, revertClaudeConversation, revertClaudeFiles } from "./rewind.js";
|
|
17
17
|
import { normalizeProviderReplayTimestamp } from "../../provider-history-timestamps.js";
|
|
18
18
|
import { claudeProjectDirSync } from "./project-dir.js";
|
|
19
|
+
import { SETTING_APPLIES_NEXT_TURN_NOTICE } from "../../provider-notices.js";
|
|
19
20
|
import { getAgentStreamEventTurnId, } from "../../agent-sdk-types.js";
|
|
20
21
|
import { importSessionFromPersistence } from "../../provider-session-import.js";
|
|
21
22
|
import { checkProviderLaunchAvailable, createProviderEnv, createProviderEnvSpec, resolveProviderLaunch, } from "../../provider-launch-config.js";
|
|
@@ -228,6 +229,9 @@ function isClaudeThinkingEffort(value) {
|
|
|
228
229
|
value === "xhigh" ||
|
|
229
230
|
value === "max");
|
|
230
231
|
}
|
|
232
|
+
function isClaudeThinkingOption(value) {
|
|
233
|
+
return value === "ultracode" || isClaudeThinkingEffort(value);
|
|
234
|
+
}
|
|
231
235
|
const MAX_RECENT_STDERR_CHARS = 4000;
|
|
232
236
|
const STDERR_FLUSH_WAIT_MS = 150;
|
|
233
237
|
const STDERR_FLUSH_POLL_INTERVAL_MS = 10;
|
|
@@ -1099,6 +1103,9 @@ export class ClaudeAgentClient {
|
|
|
1099
1103
|
}
|
|
1100
1104
|
return {
|
|
1101
1105
|
diagnostic: formatProviderDiagnostic("Claude Code", [
|
|
1106
|
+
...(await buildCommandResolutionDiagnosticRows(launch, {
|
|
1107
|
+
knownBinaryNames: ["claude"],
|
|
1108
|
+
})),
|
|
1102
1109
|
...(await buildBinaryDiagnosticRows(launch, availability)),
|
|
1103
1110
|
...(auth ? [{ label: "Auth", value: auth }] : []),
|
|
1104
1111
|
{ label: "Models", value: modelsValue },
|
|
@@ -1180,21 +1187,21 @@ function extractContextWindowSize(modelUsage) {
|
|
|
1180
1187
|
}
|
|
1181
1188
|
return maxContextWindow;
|
|
1182
1189
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1190
|
+
function resolveInitialContextWindowSize(modelId) {
|
|
1191
|
+
const normalized = typeof modelId === "string" ? modelId.trim().toLowerCase() : "";
|
|
1192
|
+
if (!normalized) {
|
|
1185
1193
|
return undefined;
|
|
1186
1194
|
}
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
return undefined;
|
|
1195
|
+
if (normalized.includes("[1m]") || normalized.includes("context-1m")) {
|
|
1196
|
+
return 1000000;
|
|
1190
1197
|
}
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
return
|
|
1198
|
+
if (normalized.includes("claude-fable-5")) {
|
|
1199
|
+
return 1000000;
|
|
1200
|
+
}
|
|
1201
|
+
if (/(?:^|[~/_-])(?:claude[-_ ]*)?(opus|sonnet|haiku)(?:$|[-_ ./])/.test(normalized)) {
|
|
1202
|
+
return 200000;
|
|
1203
|
+
}
|
|
1204
|
+
return undefined;
|
|
1198
1205
|
}
|
|
1199
1206
|
function readStreamRequestInputTokens(event) {
|
|
1200
1207
|
const messageUsage = toObjectRecord(toObjectRecord(event.message)?.usage);
|
|
@@ -1225,6 +1232,172 @@ function readStreamRequestOutputTokens(event) {
|
|
|
1225
1232
|
}
|
|
1226
1233
|
return outputTokens;
|
|
1227
1234
|
}
|
|
1235
|
+
function readLastUsageIteration(usage) {
|
|
1236
|
+
const iterations = toObjectRecord(usage)?.iterations;
|
|
1237
|
+
if (!Array.isArray(iterations)) {
|
|
1238
|
+
return undefined;
|
|
1239
|
+
}
|
|
1240
|
+
for (let index = iterations.length - 1; index >= 0; index -= 1) {
|
|
1241
|
+
const candidate = toObjectRecord(iterations[index]);
|
|
1242
|
+
if (candidate) {
|
|
1243
|
+
return candidate;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return undefined;
|
|
1247
|
+
}
|
|
1248
|
+
function readUsageTokenTotal(usage) {
|
|
1249
|
+
const usageWithCacheCreation = usage;
|
|
1250
|
+
const inputTokens = typeof usage.input_tokens === "number" && Number.isFinite(usage.input_tokens)
|
|
1251
|
+
? usage.input_tokens
|
|
1252
|
+
: 0;
|
|
1253
|
+
const cacheCreationInputTokens = typeof usageWithCacheCreation.cache_creation_input_tokens === "number" &&
|
|
1254
|
+
Number.isFinite(usageWithCacheCreation.cache_creation_input_tokens)
|
|
1255
|
+
? usageWithCacheCreation.cache_creation_input_tokens
|
|
1256
|
+
: 0;
|
|
1257
|
+
const cacheReadInputTokens = typeof usage.cache_read_input_tokens === "number" &&
|
|
1258
|
+
Number.isFinite(usage.cache_read_input_tokens)
|
|
1259
|
+
? usage.cache_read_input_tokens
|
|
1260
|
+
: 0;
|
|
1261
|
+
const outputTokens = typeof usage.output_tokens === "number" && Number.isFinite(usage.output_tokens)
|
|
1262
|
+
? usage.output_tokens
|
|
1263
|
+
: 0;
|
|
1264
|
+
const total = inputTokens + cacheCreationInputTokens + cacheReadInputTokens + outputTokens;
|
|
1265
|
+
return total > 0 ? total : undefined;
|
|
1266
|
+
}
|
|
1267
|
+
function readActiveUsageTokens(usage) {
|
|
1268
|
+
const activeUsage = readLastUsageIteration(usage);
|
|
1269
|
+
return activeUsage ? readUsageTokenTotal(activeUsage) : undefined;
|
|
1270
|
+
}
|
|
1271
|
+
function readLegacyResultUsageTokens(usage) {
|
|
1272
|
+
const usageRecord = toObjectRecord(usage);
|
|
1273
|
+
return usageRecord ? readUsageTokenTotal(usageRecord) : undefined;
|
|
1274
|
+
}
|
|
1275
|
+
function readCurrentContextUsage(value) {
|
|
1276
|
+
const record = toObjectRecord(value);
|
|
1277
|
+
if (!record) {
|
|
1278
|
+
return undefined;
|
|
1279
|
+
}
|
|
1280
|
+
const totalTokens = record.totalTokens;
|
|
1281
|
+
if (typeof totalTokens !== "number" || !Number.isFinite(totalTokens) || totalTokens < 0) {
|
|
1282
|
+
return undefined;
|
|
1283
|
+
}
|
|
1284
|
+
const maxTokens = record.maxTokens;
|
|
1285
|
+
return {
|
|
1286
|
+
totalTokens,
|
|
1287
|
+
...(typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0
|
|
1288
|
+
? { maxTokens }
|
|
1289
|
+
: {}),
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
function isClaudeSubagentToolName(name) {
|
|
1293
|
+
return name === "Task" || name === "Agent";
|
|
1294
|
+
}
|
|
1295
|
+
class ClaudeContextUsageState {
|
|
1296
|
+
constructor(initialContextWindowMaxTokens) {
|
|
1297
|
+
this.completedResultTurns = 0;
|
|
1298
|
+
this.contextWindowMaxTokens = initialContextWindowMaxTokens;
|
|
1299
|
+
}
|
|
1300
|
+
beginTurn() {
|
|
1301
|
+
this.streamRequestInputTokens = undefined;
|
|
1302
|
+
this.streamRequestOutputTokens = undefined;
|
|
1303
|
+
}
|
|
1304
|
+
setInitialContextWindowMaxTokens(contextWindowMaxTokens) {
|
|
1305
|
+
this.contextWindowMaxTokens = contextWindowMaxTokens;
|
|
1306
|
+
}
|
|
1307
|
+
recordModelUsage(modelUsage) {
|
|
1308
|
+
const contextWindowMaxTokens = extractContextWindowSize(modelUsage);
|
|
1309
|
+
if (contextWindowMaxTokens !== undefined) {
|
|
1310
|
+
this.contextWindowMaxTokens = contextWindowMaxTokens;
|
|
1311
|
+
}
|
|
1312
|
+
return this.contextWindowMaxTokens;
|
|
1313
|
+
}
|
|
1314
|
+
recordCurrentContextUsage(usage) {
|
|
1315
|
+
if (usage?.maxTokens !== undefined) {
|
|
1316
|
+
this.contextWindowMaxTokens = usage.maxTokens;
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
buildStreamUsageEvent(event) {
|
|
1320
|
+
const streamEvent = toObjectRecord(event);
|
|
1321
|
+
if (!streamEvent) {
|
|
1322
|
+
return null;
|
|
1323
|
+
}
|
|
1324
|
+
const eventType = readTrimmedString(streamEvent.type);
|
|
1325
|
+
if (eventType === "message_start") {
|
|
1326
|
+
const inputTokens = readStreamRequestInputTokens(streamEvent);
|
|
1327
|
+
if (typeof inputTokens !== "number") {
|
|
1328
|
+
return null;
|
|
1329
|
+
}
|
|
1330
|
+
this.streamRequestInputTokens = inputTokens;
|
|
1331
|
+
this.streamRequestOutputTokens = 0;
|
|
1332
|
+
}
|
|
1333
|
+
else if (eventType === "message_delta") {
|
|
1334
|
+
const outputTokens = readStreamRequestOutputTokens(streamEvent);
|
|
1335
|
+
if (typeof outputTokens !== "number") {
|
|
1336
|
+
return null;
|
|
1337
|
+
}
|
|
1338
|
+
this.streamRequestOutputTokens = outputTokens;
|
|
1339
|
+
}
|
|
1340
|
+
else {
|
|
1341
|
+
return null;
|
|
1342
|
+
}
|
|
1343
|
+
const usedTokens = this.streamUsedTokens();
|
|
1344
|
+
if (usedTokens === undefined) {
|
|
1345
|
+
return null;
|
|
1346
|
+
}
|
|
1347
|
+
return this.createUsageUpdatedEvent(usedTokens);
|
|
1348
|
+
}
|
|
1349
|
+
buildResultUsage(message, modelUsage, currentContextUsage) {
|
|
1350
|
+
try {
|
|
1351
|
+
if (!message.usage) {
|
|
1352
|
+
return undefined;
|
|
1353
|
+
}
|
|
1354
|
+
const usage = {
|
|
1355
|
+
inputTokens: message.usage.input_tokens,
|
|
1356
|
+
cachedInputTokens: message.usage.cache_read_input_tokens,
|
|
1357
|
+
outputTokens: message.usage.output_tokens,
|
|
1358
|
+
totalCostUsd: message.total_cost_usd,
|
|
1359
|
+
};
|
|
1360
|
+
const modelContextWindowMaxTokens = this.recordModelUsage(modelUsage ?? message.modelUsage);
|
|
1361
|
+
this.recordCurrentContextUsage(currentContextUsage);
|
|
1362
|
+
if (this.contextWindowMaxTokens !== undefined) {
|
|
1363
|
+
usage.contextWindowMaxTokens = this.contextWindowMaxTokens;
|
|
1364
|
+
}
|
|
1365
|
+
else if (modelContextWindowMaxTokens !== undefined) {
|
|
1366
|
+
usage.contextWindowMaxTokens = modelContextWindowMaxTokens;
|
|
1367
|
+
}
|
|
1368
|
+
const activeResultUsageTokens = readActiveUsageTokens(message.usage) ??
|
|
1369
|
+
(this.completedResultTurns === 0 ? readLegacyResultUsageTokens(message.usage) : undefined);
|
|
1370
|
+
const usedTokens = currentContextUsage?.totalTokens ?? this.streamUsedTokens() ?? activeResultUsageTokens;
|
|
1371
|
+
if (usedTokens !== undefined) {
|
|
1372
|
+
usage.contextWindowUsedTokens = usedTokens;
|
|
1373
|
+
}
|
|
1374
|
+
return usage;
|
|
1375
|
+
}
|
|
1376
|
+
finally {
|
|
1377
|
+
this.completedResultTurns += 1;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
streamUsedTokens() {
|
|
1381
|
+
if (typeof this.streamRequestInputTokens !== "number" ||
|
|
1382
|
+
typeof this.streamRequestOutputTokens !== "number") {
|
|
1383
|
+
return undefined;
|
|
1384
|
+
}
|
|
1385
|
+
return this.streamRequestInputTokens + this.streamRequestOutputTokens;
|
|
1386
|
+
}
|
|
1387
|
+
createUsageUpdatedEvent(contextWindowUsedTokens) {
|
|
1388
|
+
const usage = {
|
|
1389
|
+
contextWindowUsedTokens,
|
|
1390
|
+
};
|
|
1391
|
+
if (this.contextWindowMaxTokens !== undefined) {
|
|
1392
|
+
usage.contextWindowMaxTokens = this.contextWindowMaxTokens;
|
|
1393
|
+
}
|
|
1394
|
+
return {
|
|
1395
|
+
type: "usage_updated",
|
|
1396
|
+
provider: "claude",
|
|
1397
|
+
usage,
|
|
1398
|
+
};
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1228
1401
|
class ClaudeAgentSession {
|
|
1229
1402
|
constructor(config, options) {
|
|
1230
1403
|
this.provider = "claude";
|
|
@@ -1344,6 +1517,7 @@ class ClaudeAgentSession {
|
|
|
1344
1517
|
this.logger = options.logger.child({ agentId: this.agentId });
|
|
1345
1518
|
this.queryFactory = options.queryFactory;
|
|
1346
1519
|
this.resolveBinary = options.resolveBinary;
|
|
1520
|
+
this.contextUsage = new ClaudeContextUsageState(resolveInitialContextWindowSize(this.config.model));
|
|
1347
1521
|
const handle = options.handle;
|
|
1348
1522
|
if (handle) {
|
|
1349
1523
|
if (!handle.sessionId) {
|
|
@@ -1441,6 +1615,7 @@ class ClaudeAgentSession {
|
|
|
1441
1615
|
this.activeForegroundTurnId = turnId;
|
|
1442
1616
|
this.foregroundHasVisibleActivity = false;
|
|
1443
1617
|
this.activeTurnHasAssistantText = false;
|
|
1618
|
+
this.contextUsage.beginTurn();
|
|
1444
1619
|
this.transitionTurnState("foreground", "foreground turn started");
|
|
1445
1620
|
this.clearRecentStderr();
|
|
1446
1621
|
let cancelIssued = false;
|
|
@@ -1550,6 +1725,7 @@ class ClaudeAgentSession {
|
|
|
1550
1725
|
if (!claudeModelSupportsFastMode(this.config.model) && this.config.featureValues?.fast_mode) {
|
|
1551
1726
|
await this.applyFastModeFeature(false, activeQuery);
|
|
1552
1727
|
}
|
|
1728
|
+
this.contextUsage.setInitialContextWindowMaxTokens(resolveInitialContextWindowSize(this.config.model));
|
|
1553
1729
|
this.lastOptionsModel = normalizedModelId ?? this.lastOptionsModel;
|
|
1554
1730
|
this.lastRuntimeModel = null;
|
|
1555
1731
|
this.cachedRuntimeInfo = null;
|
|
@@ -1563,13 +1739,16 @@ class ClaudeAgentSession {
|
|
|
1563
1739
|
if (!normalizedThinkingOptionId || normalizedThinkingOptionId === "default") {
|
|
1564
1740
|
this.config.thinkingOptionId = undefined;
|
|
1565
1741
|
}
|
|
1566
|
-
else if (
|
|
1742
|
+
else if (isClaudeThinkingOption(normalizedThinkingOptionId)) {
|
|
1567
1743
|
this.config.thinkingOptionId = normalizedThinkingOptionId;
|
|
1568
1744
|
}
|
|
1569
1745
|
else {
|
|
1570
1746
|
throw new Error(`Unknown thinking option: ${normalizedThinkingOptionId}`);
|
|
1571
1747
|
}
|
|
1572
1748
|
this.queryRestartNeeded = true;
|
|
1749
|
+
if (this.activeForegroundTurnId || this.autonomousTurn) {
|
|
1750
|
+
return SETTING_APPLIES_NEXT_TURN_NOTICE;
|
|
1751
|
+
}
|
|
1573
1752
|
}
|
|
1574
1753
|
async setFeature(featureId, value) {
|
|
1575
1754
|
if (featureId !== "fast_mode") {
|
|
@@ -2096,10 +2275,13 @@ class ClaudeAgentSession {
|
|
|
2096
2275
|
const thinkingOptionId = this.config.thinkingOptionId && this.config.thinkingOptionId !== "default"
|
|
2097
2276
|
? this.config.thinkingOptionId
|
|
2098
2277
|
: undefined;
|
|
2278
|
+
if (thinkingOptionId === "ultracode") {
|
|
2279
|
+
return { thinking: { type: "adaptive" }, effort: "xhigh", ultracode: true };
|
|
2280
|
+
}
|
|
2099
2281
|
if (thinkingOptionId && isClaudeThinkingEffort(thinkingOptionId)) {
|
|
2100
|
-
return { thinking: { type: "adaptive" }, effort: thinkingOptionId };
|
|
2282
|
+
return { thinking: { type: "adaptive" }, effort: thinkingOptionId, ultracode: false };
|
|
2101
2283
|
}
|
|
2102
|
-
return { thinking: undefined, effort: undefined };
|
|
2284
|
+
return { thinking: undefined, effort: undefined, ultracode: false };
|
|
2103
2285
|
}
|
|
2104
2286
|
buildAppendedSystemPrompt() {
|
|
2105
2287
|
return (composeSystemPromptParts(this.config.systemPrompt, this.config.daemonAppendSystemPrompt) ?? "");
|
|
@@ -2120,10 +2302,10 @@ class ClaudeAgentSession {
|
|
|
2120
2302
|
});
|
|
2121
2303
|
}
|
|
2122
2304
|
async buildOptions() {
|
|
2123
|
-
const { thinking, effort } = this.resolveThinkingConfig();
|
|
2305
|
+
const { thinking, effort, ultracode } = this.resolveThinkingConfig();
|
|
2124
2306
|
const appendedSystemPrompt = this.buildAppendedSystemPrompt();
|
|
2125
2307
|
const extraClaudeOptions = this.config.extra?.claude;
|
|
2126
|
-
const
|
|
2308
|
+
const settingsOptions = this.buildSettingsOptions(extraClaudeOptions, { ultracode });
|
|
2127
2309
|
const sdkEnv = this.buildSdkEnv(extraClaudeOptions);
|
|
2128
2310
|
assertClaudeAutoModeEligible(this.currentMode, sdkEnv);
|
|
2129
2311
|
const claudeBinary = await this.resolveBinary();
|
|
@@ -2172,7 +2354,7 @@ class ClaudeAgentSession {
|
|
|
2172
2354
|
...(thinking ? { thinking } : {}),
|
|
2173
2355
|
...(effort ? { effort } : {}),
|
|
2174
2356
|
...extraClaudeOptions,
|
|
2175
|
-
...
|
|
2357
|
+
...settingsOptions,
|
|
2176
2358
|
...(this.persistSession === undefined ? {} : { persistSession: this.persistSession }),
|
|
2177
2359
|
env: sdkEnv,
|
|
2178
2360
|
};
|
|
@@ -2194,12 +2376,17 @@ class ClaudeAgentSession {
|
|
|
2194
2376
|
}
|
|
2195
2377
|
return base;
|
|
2196
2378
|
}
|
|
2197
|
-
|
|
2379
|
+
buildSettingsOptions(extraClaudeOptions, input) {
|
|
2198
2380
|
const fastMode = this.resolveFastModeSetting();
|
|
2199
|
-
if (fastMode === null) {
|
|
2381
|
+
if (fastMode === null && !input.ultracode) {
|
|
2200
2382
|
return {};
|
|
2201
2383
|
}
|
|
2202
|
-
return {
|
|
2384
|
+
return {
|
|
2385
|
+
settings: mergeClaudeSettings(extraClaudeOptions?.settings, {
|
|
2386
|
+
...(fastMode === null ? {} : { fastMode }),
|
|
2387
|
+
...(input.ultracode ? { ultracode: true } : {}),
|
|
2388
|
+
}),
|
|
2389
|
+
};
|
|
2203
2390
|
}
|
|
2204
2391
|
resolveFastModeSetting() {
|
|
2205
2392
|
if (!claudeModelSupportsFastMode(this.config.model)) {
|
|
@@ -2413,6 +2600,7 @@ class ClaudeAgentSession {
|
|
|
2413
2600
|
id: this.createTurnId("autonomous"),
|
|
2414
2601
|
};
|
|
2415
2602
|
this.activeTurnHasAssistantText = false;
|
|
2603
|
+
this.contextUsage.beginTurn();
|
|
2416
2604
|
this.notifySubscribers({ type: "turn_started", provider: "claude" });
|
|
2417
2605
|
this.syncTurnState("autonomous turn started");
|
|
2418
2606
|
}
|
|
@@ -2491,7 +2679,7 @@ class ClaudeAgentSession {
|
|
|
2491
2679
|
if (await this.handleMissingResumedConversation(message, activeQuery)) {
|
|
2492
2680
|
return true;
|
|
2493
2681
|
}
|
|
2494
|
-
this.routeSdkMessageFromPump(message);
|
|
2682
|
+
await this.routeSdkMessageFromPump(message, activeQuery);
|
|
2495
2683
|
return false;
|
|
2496
2684
|
};
|
|
2497
2685
|
const drainActiveQuery = async () => {
|
|
@@ -2559,7 +2747,7 @@ class ClaudeAgentSession {
|
|
|
2559
2747
|
message.type === "tool_progress" ||
|
|
2560
2748
|
(message.type === "system" && message.subtype === "task_notification"));
|
|
2561
2749
|
}
|
|
2562
|
-
routeSdkMessageFromPump(message) {
|
|
2750
|
+
async routeSdkMessageFromPump(message, activeQuery) {
|
|
2563
2751
|
if (this.shouldSuppressStaleResult(message)) {
|
|
2564
2752
|
return;
|
|
2565
2753
|
}
|
|
@@ -2582,22 +2770,7 @@ class ClaudeAgentSession {
|
|
|
2582
2770
|
identifiers,
|
|
2583
2771
|
rawEvent: message,
|
|
2584
2772
|
}, "provider.claude.parsed_event");
|
|
2585
|
-
const
|
|
2586
|
-
suppressAssistantText: true,
|
|
2587
|
-
suppressReasoning: true,
|
|
2588
|
-
});
|
|
2589
|
-
const assistantTimelineEvents = this.timelineAssembler
|
|
2590
|
-
.consume({
|
|
2591
|
-
message,
|
|
2592
|
-
runId: turnId,
|
|
2593
|
-
messageIdHint: identifiers.messageId,
|
|
2594
|
-
})
|
|
2595
|
-
.map((item) => ({
|
|
2596
|
-
type: "timeline",
|
|
2597
|
-
item,
|
|
2598
|
-
provider: "claude",
|
|
2599
|
-
}));
|
|
2600
|
-
const events = [...messageEvents, ...assistantTimelineEvents];
|
|
2773
|
+
const events = await this.buildPumpedMessageEvents(message, activeQuery, identifiers.messageId, turnId);
|
|
2601
2774
|
if (events.length === 0) {
|
|
2602
2775
|
return;
|
|
2603
2776
|
}
|
|
@@ -2620,6 +2793,38 @@ class ClaudeAgentSession {
|
|
|
2620
2793
|
}
|
|
2621
2794
|
this.dispatchEvents(events);
|
|
2622
2795
|
}
|
|
2796
|
+
async buildPumpedMessageEvents(message, activeQuery, messageIdHint, turnId) {
|
|
2797
|
+
const currentContextUsage = message.type === "result" && message.subtype === "success"
|
|
2798
|
+
? await this.queryCurrentContextUsage(activeQuery)
|
|
2799
|
+
: undefined;
|
|
2800
|
+
const messageEvents = this.translateMessageToEvents(message, {
|
|
2801
|
+
suppressAssistantText: true,
|
|
2802
|
+
suppressReasoning: true,
|
|
2803
|
+
currentContextUsage,
|
|
2804
|
+
});
|
|
2805
|
+
const assistantTimelineEvents = this.timelineAssembler
|
|
2806
|
+
.consume({
|
|
2807
|
+
message,
|
|
2808
|
+
runId: turnId,
|
|
2809
|
+
messageIdHint,
|
|
2810
|
+
})
|
|
2811
|
+
.map((item) => ({
|
|
2812
|
+
type: "timeline",
|
|
2813
|
+
item,
|
|
2814
|
+
provider: "claude",
|
|
2815
|
+
}));
|
|
2816
|
+
return [...messageEvents, ...assistantTimelineEvents];
|
|
2817
|
+
}
|
|
2818
|
+
async queryCurrentContextUsage(activeQuery) {
|
|
2819
|
+
try {
|
|
2820
|
+
const usage = await withTimeout(activeQuery.getContextUsage(), 3000, "timeout");
|
|
2821
|
+
return readCurrentContextUsage(usage);
|
|
2822
|
+
}
|
|
2823
|
+
catch (error) {
|
|
2824
|
+
this.logger.debug({ err: error }, "Claude context usage query failed");
|
|
2825
|
+
return undefined;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2623
2828
|
async handleMissingResumedConversation(message, activeQuery) {
|
|
2624
2829
|
const staleResumeError = this.readMissingResumedConversationError(message);
|
|
2625
2830
|
if (!staleResumeError) {
|
|
@@ -2710,7 +2915,9 @@ class ClaudeAgentSession {
|
|
|
2710
2915
|
this.appendStreamEventEvents(message, events, options);
|
|
2711
2916
|
break;
|
|
2712
2917
|
case "result":
|
|
2713
|
-
this.appendResultEvents(message, events
|
|
2918
|
+
this.appendResultEvents(message, events, {
|
|
2919
|
+
currentContextUsage: options?.currentContextUsage,
|
|
2920
|
+
});
|
|
2714
2921
|
break;
|
|
2715
2922
|
default:
|
|
2716
2923
|
break;
|
|
@@ -2783,22 +2990,18 @@ class ClaudeAgentSession {
|
|
|
2783
2990
|
return;
|
|
2784
2991
|
}
|
|
2785
2992
|
if (message.subtype === "task_progress") {
|
|
2786
|
-
|
|
2787
|
-
readContextWindowUsedTokensFromTaskProgress(message) ?? this.lastContextWindowUsedTokens;
|
|
2788
|
-
if (typeof this.lastContextWindowUsedTokens === "number") {
|
|
2789
|
-
events.push(this.createUsageUpdatedEvent(this.lastContextWindowUsedTokens));
|
|
2790
|
-
}
|
|
2993
|
+
return;
|
|
2791
2994
|
}
|
|
2792
2995
|
}
|
|
2793
2996
|
appendTaskNotificationEvents(message, events) {
|
|
2794
2997
|
// TODO: subagent timelines are best-effort. Subagent task_notifications
|
|
2795
2998
|
// arrive without parent_tool_use_id but with tool_use_id pointing at the
|
|
2796
|
-
// parent's
|
|
2999
|
+
// the parent's subagent tool call, so they slip past the sidechain router and pollute
|
|
2797
3000
|
// the parent timeline. Drop them here; eventually thread them into the
|
|
2798
|
-
// parent
|
|
3001
|
+
// parent tool call's sub_agent log instead.
|
|
2799
3002
|
const taskUseId = message.tool_use_id;
|
|
2800
3003
|
const cachedTool = taskUseId ? this.toolUseCache.get(taskUseId) : undefined;
|
|
2801
|
-
if (cachedTool?.name
|
|
3004
|
+
if (isClaudeSubagentToolName(cachedTool?.name)) {
|
|
2802
3005
|
return;
|
|
2803
3006
|
}
|
|
2804
3007
|
const taskNotificationItem = mapTaskNotificationSystemRecordToToolCall(message);
|
|
@@ -2809,11 +3012,6 @@ class ClaudeAgentSession {
|
|
|
2809
3012
|
provider: "claude",
|
|
2810
3013
|
});
|
|
2811
3014
|
}
|
|
2812
|
-
const usage = readUsageFromTaskNotification(message);
|
|
2813
|
-
if (typeof usage === "number") {
|
|
2814
|
-
this.lastContextWindowUsedTokens = usage;
|
|
2815
|
-
events.push(this.createUsageUpdatedEvent(usage));
|
|
2816
|
-
}
|
|
2817
3015
|
}
|
|
2818
3016
|
appendUserMessageEvents(message, events) {
|
|
2819
3017
|
if (isSyntheticUserEntry(message)) {
|
|
@@ -2877,7 +3075,7 @@ class ClaudeAgentSession {
|
|
|
2877
3075
|
}
|
|
2878
3076
|
}
|
|
2879
3077
|
appendStreamEventEvents(message, events, options) {
|
|
2880
|
-
const usageUpdatedEvent = this.
|
|
3078
|
+
const usageUpdatedEvent = this.contextUsage.buildStreamUsageEvent(message.event);
|
|
2881
3079
|
if (usageUpdatedEvent) {
|
|
2882
3080
|
events.push(usageUpdatedEvent);
|
|
2883
3081
|
}
|
|
@@ -2889,8 +3087,8 @@ class ClaudeAgentSession {
|
|
|
2889
3087
|
events.push({ type: "timeline", item, provider: "claude" });
|
|
2890
3088
|
}
|
|
2891
3089
|
}
|
|
2892
|
-
appendResultEvents(message, events) {
|
|
2893
|
-
const usage = this.convertUsage(message, message.modelUsage);
|
|
3090
|
+
appendResultEvents(message, events, options) {
|
|
3091
|
+
const usage = this.convertUsage(message, message.modelUsage, options?.currentContextUsage);
|
|
2894
3092
|
if (message.subtype === "success") {
|
|
2895
3093
|
// Built-in slash commands (e.g. /voice, /usage, "Unknown command: …")
|
|
2896
3094
|
// run client-side in the Claude CLI with no model turn — output_tokens
|
|
@@ -3034,92 +3232,8 @@ class ClaudeAgentSession {
|
|
|
3034
3232
|
}
|
|
3035
3233
|
return null;
|
|
3036
3234
|
}
|
|
3037
|
-
convertUsage(message, modelUsage) {
|
|
3038
|
-
|
|
3039
|
-
return undefined;
|
|
3040
|
-
}
|
|
3041
|
-
const usage = {
|
|
3042
|
-
inputTokens: message.usage.input_tokens,
|
|
3043
|
-
cachedInputTokens: message.usage.cache_read_input_tokens,
|
|
3044
|
-
outputTokens: message.usage.output_tokens,
|
|
3045
|
-
totalCostUsd: message.total_cost_usd,
|
|
3046
|
-
};
|
|
3047
|
-
const contextWindowMaxTokens = extractContextWindowSize(modelUsage ?? message.modelUsage);
|
|
3048
|
-
if (contextWindowMaxTokens !== undefined) {
|
|
3049
|
-
this.lastContextWindowMaxTokens = contextWindowMaxTokens;
|
|
3050
|
-
usage.contextWindowMaxTokens = contextWindowMaxTokens;
|
|
3051
|
-
}
|
|
3052
|
-
else if (this.lastContextWindowMaxTokens !== undefined) {
|
|
3053
|
-
usage.contextWindowMaxTokens = this.lastContextWindowMaxTokens;
|
|
3054
|
-
}
|
|
3055
|
-
if (typeof this.lastContextWindowUsedTokens === "number") {
|
|
3056
|
-
// task_progress.total_tokens is the accurate context window fill level.
|
|
3057
|
-
// Prefer it over result.usage which contains accumulated session totals.
|
|
3058
|
-
usage.contextWindowUsedTokens = this.lastContextWindowUsedTokens;
|
|
3059
|
-
}
|
|
3060
|
-
else if (typeof this.lastStreamRequestInputTokens === "number" &&
|
|
3061
|
-
typeof this.lastStreamRequestOutputTokens === "number") {
|
|
3062
|
-
usage.contextWindowUsedTokens =
|
|
3063
|
-
this.lastStreamRequestInputTokens + this.lastStreamRequestOutputTokens;
|
|
3064
|
-
}
|
|
3065
|
-
else if (message.usage) {
|
|
3066
|
-
// Fallback: derive from result.usage when no task_progress has been
|
|
3067
|
-
// received yet. These values are accumulated across all API calls, but
|
|
3068
|
-
// for the first turn they equal the per-call values so the estimate is
|
|
3069
|
-
// reasonable. Once a task_progress arrives it takes over permanently.
|
|
3070
|
-
const usageWithCacheCreation = message.usage;
|
|
3071
|
-
const derived = (message.usage.input_tokens ?? 0) +
|
|
3072
|
-
(usageWithCacheCreation.cache_creation_input_tokens ?? 0) +
|
|
3073
|
-
(message.usage.cache_read_input_tokens ?? 0) +
|
|
3074
|
-
(message.usage.output_tokens ?? 0);
|
|
3075
|
-
if (Number.isFinite(derived) && derived > 0) {
|
|
3076
|
-
usage.contextWindowUsedTokens = derived;
|
|
3077
|
-
}
|
|
3078
|
-
}
|
|
3079
|
-
return usage;
|
|
3080
|
-
}
|
|
3081
|
-
createUsageUpdatedEvent(contextWindowUsedTokens) {
|
|
3082
|
-
const usage = {
|
|
3083
|
-
contextWindowUsedTokens,
|
|
3084
|
-
};
|
|
3085
|
-
if (this.lastContextWindowMaxTokens !== undefined) {
|
|
3086
|
-
usage.contextWindowMaxTokens = this.lastContextWindowMaxTokens;
|
|
3087
|
-
}
|
|
3088
|
-
return {
|
|
3089
|
-
type: "usage_updated",
|
|
3090
|
-
provider: "claude",
|
|
3091
|
-
usage,
|
|
3092
|
-
};
|
|
3093
|
-
}
|
|
3094
|
-
trackStreamEventUsage(event) {
|
|
3095
|
-
const streamEvent = toObjectRecord(event);
|
|
3096
|
-
if (!streamEvent) {
|
|
3097
|
-
return null;
|
|
3098
|
-
}
|
|
3099
|
-
const eventType = readTrimmedString(streamEvent.type);
|
|
3100
|
-
if (eventType === "message_start") {
|
|
3101
|
-
const inputTokens = readStreamRequestInputTokens(streamEvent);
|
|
3102
|
-
if (typeof inputTokens !== "number") {
|
|
3103
|
-
return null;
|
|
3104
|
-
}
|
|
3105
|
-
this.lastStreamRequestInputTokens = inputTokens;
|
|
3106
|
-
this.lastStreamRequestOutputTokens = 0;
|
|
3107
|
-
}
|
|
3108
|
-
else if (eventType === "message_delta") {
|
|
3109
|
-
const outputTokens = readStreamRequestOutputTokens(streamEvent);
|
|
3110
|
-
if (typeof outputTokens !== "number") {
|
|
3111
|
-
return null;
|
|
3112
|
-
}
|
|
3113
|
-
this.lastStreamRequestOutputTokens = outputTokens;
|
|
3114
|
-
}
|
|
3115
|
-
else {
|
|
3116
|
-
return null;
|
|
3117
|
-
}
|
|
3118
|
-
if (typeof this.lastStreamRequestInputTokens !== "number" ||
|
|
3119
|
-
typeof this.lastStreamRequestOutputTokens !== "number") {
|
|
3120
|
-
return null;
|
|
3121
|
-
}
|
|
3122
|
-
return this.createUsageUpdatedEvent(this.lastStreamRequestInputTokens + this.lastStreamRequestOutputTokens);
|
|
3235
|
+
convertUsage(message, modelUsage, currentContextUsage) {
|
|
3236
|
+
return this.contextUsage.buildResultUsage(message, modelUsage, currentContextUsage);
|
|
3123
3237
|
}
|
|
3124
3238
|
enqueueTimeline(item) {
|
|
3125
3239
|
this.pushEvent({ type: "timeline", item, provider: "claude" });
|
|
@@ -14,20 +14,24 @@ const CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS = [
|
|
|
14
14
|
{ id: "xhigh", label: "Extra High" },
|
|
15
15
|
{ id: "max", label: "Max" },
|
|
16
16
|
];
|
|
17
|
+
const CLAUDE_ULTRACODE_THINKING_OPTIONS = [
|
|
18
|
+
...CLAUDE_OPUS_EXTENDED_THINKING_OPTIONS,
|
|
19
|
+
{ id: "ultracode", label: "Ultracode" },
|
|
20
|
+
];
|
|
17
21
|
const CLAUDE_MODELS = [
|
|
18
22
|
{
|
|
19
23
|
provider: "claude",
|
|
20
24
|
id: "claude-fable-5",
|
|
21
25
|
label: "Fable 5",
|
|
22
26
|
description: "Fable 5 · Most powerful model",
|
|
23
|
-
thinkingOptions: [...
|
|
27
|
+
thinkingOptions: [...CLAUDE_ULTRACODE_THINKING_OPTIONS],
|
|
24
28
|
},
|
|
25
29
|
{
|
|
26
30
|
provider: "claude",
|
|
27
31
|
id: "claude-opus-4-8[1m]",
|
|
28
32
|
label: "Opus 4.8 1M",
|
|
29
33
|
description: "Opus 4.8 with 1M context window",
|
|
30
|
-
thinkingOptions: [...
|
|
34
|
+
thinkingOptions: [...CLAUDE_ULTRACODE_THINKING_OPTIONS],
|
|
31
35
|
},
|
|
32
36
|
{
|
|
33
37
|
provider: "claude",
|
|
@@ -35,7 +39,7 @@ const CLAUDE_MODELS = [
|
|
|
35
39
|
label: "Opus 4.8",
|
|
36
40
|
description: "Opus 4.8 · Latest release",
|
|
37
41
|
isDefault: true,
|
|
38
|
-
thinkingOptions: [...
|
|
42
|
+
thinkingOptions: [...CLAUDE_ULTRACODE_THINKING_OPTIONS],
|
|
39
43
|
},
|
|
40
44
|
{
|
|
41
45
|
provider: "claude",
|
|
@@ -5,8 +5,8 @@ import { join } from "node:path";
|
|
|
5
5
|
// Verbatim port of the Claude Agent SDK's project-directory encoding so
|
|
6
6
|
// paseo computes the same `~/.claude/projects/<dir>` path the SDK does.
|
|
7
7
|
// The SDK ships only as a precompiled bundle; grep the JS source at
|
|
8
|
-
// node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs for `function
|
|
9
|
-
// `function
|
|
8
|
+
// node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs for `function Ar`,
|
|
9
|
+
// `function So`, `async function wn`, `function Dy`, `Ni=200`.
|
|
10
10
|
const PROJECT_DIR_LENGTH_CAP = 200;
|
|
11
11
|
export async function claudeProjectDir(cwd, options) {
|
|
12
12
|
const canonical = await canonicalize(cwd);
|
|
@@ -20,20 +20,23 @@ export function claudeProjectDirSync(cwd, options) {
|
|
|
20
20
|
}
|
|
21
21
|
async function canonicalize(input) {
|
|
22
22
|
try {
|
|
23
|
-
return (await realpath(input))
|
|
23
|
+
return normalizeProjectPath(await realpath(input));
|
|
24
24
|
}
|
|
25
25
|
catch {
|
|
26
|
-
return input
|
|
26
|
+
return normalizeProjectPath(input);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
function canonicalizeSync(input) {
|
|
30
30
|
try {
|
|
31
|
-
return realpathSync.native(input)
|
|
31
|
+
return normalizeProjectPath(realpathSync.native(input));
|
|
32
32
|
}
|
|
33
33
|
catch {
|
|
34
|
-
return input
|
|
34
|
+
return normalizeProjectPath(input);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
function normalizeProjectPath(input) {
|
|
38
|
+
return process.platform === "darwin" ? input.normalize("NFC") : input;
|
|
39
|
+
}
|
|
37
40
|
function encode(input) {
|
|
38
41
|
const replaced = input.replace(/[^a-zA-Z0-9]/g, "-");
|
|
39
42
|
if (replaced.length <= PROJECT_DIR_LENGTH_CAP) {
|