@chanlerdev/scorel 0.0.2 → 0.0.4
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 +55 -2
- package/dist/index.js +1162 -192
- package/dist/index.js.map +3 -3
- package/docs/CHANGELOG.md +106 -0
- package/docs/ROADMAP.md +34 -2
- package/docs/SHIP.md +1 -1
- package/docs/spec/channels.md +15 -5
- package/docs/spec/extensions.md +6 -5
- package/docs/spec/ship/S0060-relay-hosted-webui-e2e-validation.verification.md +1 -1
- package/docs/spec/ship/S0073-provider-model-profile-contract.md +6 -6
- package/docs/spec/ship/S0074-gui-model-provider-settings-split.md +1 -1
- package/docs/spec/ship/S0076-provider-modal-search-and-direct-key.md +1 -1
- package/docs/spec/ship/S0086-auto-compact-and-session-memory.md +1 -1
- package/docs/spec/ship/S0087-gui-ui-polish-sweep.md +153 -0
- package/docs/spec/ship/S0088-gui-streaming-thinking-contract.md +35 -0
- package/docs/spec/ship/S0089-memory-reliability-and-dream-trigger.md +84 -0
- package/docs/spec/ship/S0090-gui-provider-delete-and-dark-code-theme.md +77 -0
- package/docs/spec/ship/S0091-built-in-qq-and-wechat-im-extensions.md +125 -0
- package/docs/spec/ship/S0092-im-message-media-and-human-cadence.md +83 -0
- package/docs/spec/ship/S0093-gui-im-settings-platform-layout.md +66 -0
- package/docs/spec/ship/S0094-im-inbound-runtime.md +67 -0
- package/docs/spec/ship/S0095-gui-im-session-list-refresh.md +36 -0
- package/docs/spec/ship/S0096-glob-stable-order.md +32 -0
- package/docs/spec/ship/S0097-rtk-token-saving-settings.md +61 -0
- package/docs/spec/ship/S0098-local-daemon-singleton-unified-state.md +96 -0
- package/docs/spec/ship/S0099-gui-connection-device-settings.md +85 -0
- package/docs/spec/ship/S0100-gui-provider-danger-zone.md +57 -0
- package/docs/spec/ship/S0101-gui-device-settings-polish.md +66 -0
- package/docs/spec/ship/S0102-device-only-config.md +58 -0
- package/extensions/builtin/loopback/skills/loopback/SKILL.md +2 -0
- package/extensions/builtin/qq/adapter.d.ts +27 -0
- package/extensions/builtin/qq/adapter.js +384 -0
- package/extensions/builtin/qq/scorel.extension.json +7 -0
- package/extensions/builtin/qq/skills/qq/SKILL.md +9 -0
- package/extensions/builtin/telegram/adapter.d.ts +1 -1
- package/extensions/builtin/telegram/adapter.js +7 -0
- package/extensions/builtin/telegram/skills/telegram/SKILL.md +2 -0
- package/extensions/builtin/wechat/adapter.d.ts +24 -0
- package/extensions/builtin/wechat/adapter.js +226 -0
- package/extensions/builtin/wechat/scorel.extension.json +7 -0
- package/extensions/builtin/wechat/skills/wechat/SKILL.md +9 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -257,14 +257,30 @@ var init_src2 = __esm({
|
|
|
257
257
|
this.#assertDaemonConnected();
|
|
258
258
|
return (await this.#request("fetch_provider_models", input)).models;
|
|
259
259
|
}
|
|
260
|
-
async
|
|
260
|
+
async removeModelProvider(input) {
|
|
261
|
+
this.#assertDaemonConnected();
|
|
262
|
+
return this.#request("remove_model_provider", input);
|
|
263
|
+
}
|
|
264
|
+
async getMemorySettings(input = {}) {
|
|
261
265
|
this.#assertDaemonConnected();
|
|
262
266
|
return (await this.#request("get_memory_settings", input)).memory;
|
|
263
267
|
}
|
|
268
|
+
async getMemoryStatus(input) {
|
|
269
|
+
this.#assertDaemonConnected();
|
|
270
|
+
return (await this.#request("get_memory_status", input)).status;
|
|
271
|
+
}
|
|
264
272
|
async upsertMemorySettings(input) {
|
|
265
273
|
this.#assertDaemonConnected();
|
|
266
274
|
return (await this.#request("upsert_memory_settings", input)).memory;
|
|
267
275
|
}
|
|
276
|
+
async getRuntimeSettings(input = {}) {
|
|
277
|
+
this.#assertDaemonConnected();
|
|
278
|
+
return (await this.#request("get_runtime_settings", input)).runtime;
|
|
279
|
+
}
|
|
280
|
+
async upsertRuntimeSettings(input) {
|
|
281
|
+
this.#assertDaemonConnected();
|
|
282
|
+
return (await this.#request("upsert_runtime_settings", input)).runtime;
|
|
283
|
+
}
|
|
268
284
|
async getExtensionSettings(input) {
|
|
269
285
|
this.#assertDaemonConnected();
|
|
270
286
|
return (await this.#request("get_extension_settings", input)).extension;
|
|
@@ -799,7 +815,7 @@ var init_sessions = __esm({
|
|
|
799
815
|
// packages/core/src/config/index.ts
|
|
800
816
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
801
817
|
import { join as join4 } from "node:path";
|
|
802
|
-
var SCOREL_CONFIG_SCHEMA, scorelUserRoot, scorelUserConfigPath, scorelSessionsDir,
|
|
818
|
+
var SCOREL_CONFIG_SCHEMA, scorelUserRoot, scorelUserConfigPath, scorelSessionsDir, loadScorelConfig, loadScorelConfigProfile, listProviderConnections, listAvailableModels, listProviderModels, resolveModelSelection, renderModelProfileConfig, removeProvider, renderMemoryConfig, renderRuntimeConfig, renderExtensionConfig, DEFAULT_MEMORY_CONFIG, DEFAULT_RUNTIME_CONFIG, loadMemory, loadRuntime, loadExtensions, loadProviders, loadProviderProfiles, loadProviderModels, loadAvailableModels, loadRoles, readConfigText, configPathForDevice, parseToml, parseEditableConfig, renderRawConfig, emptyRawConfig, stripComment, requireString, normalizeProviderName, requireProviderCredential, resolveProviderApiKey, providerCredentialSummary, requireNumber, requireNonNegativeNumber, requireCompactThreshold, requireBoolean, requireCustomApi, requireProviderType, requireSection, ensureSection, setConfigValue, assertKnownKey, setValue, parseTomlValue, stripTrailingSlashes, requireIdentifier, tomlString, renderTomlValue, isNodeErrorCode, requireModelRole, modelRoles;
|
|
803
819
|
var init_config = __esm({
|
|
804
820
|
"packages/core/src/config/index.ts"() {
|
|
805
821
|
"use strict";
|
|
@@ -807,8 +823,7 @@ var init_config = __esm({
|
|
|
807
823
|
fixedPaths: {
|
|
808
824
|
userRoot: "~/.scorel",
|
|
809
825
|
userConfig: "~/.scorel/config.toml",
|
|
810
|
-
sessionsDir: "~/.scorel/sessions"
|
|
811
|
-
projectConfig: ".scorel/config.toml"
|
|
826
|
+
sessionsDir: "~/.scorel/sessions"
|
|
812
827
|
},
|
|
813
828
|
sections: {
|
|
814
829
|
root: {
|
|
@@ -829,6 +844,9 @@ var init_config = __esm({
|
|
|
829
844
|
memory: {
|
|
830
845
|
keys: ["enabled", "daily", "sessionMemory", "autoDream", "promoteRoot", "dreamIdleMinutes", "autoCompactThreshold"]
|
|
831
846
|
},
|
|
847
|
+
runtime: {
|
|
848
|
+
keys: ["tokenSavingRtk"]
|
|
849
|
+
},
|
|
832
850
|
extension: {
|
|
833
851
|
keys: ["enabled", "kind"]
|
|
834
852
|
},
|
|
@@ -840,7 +858,6 @@ var init_config = __esm({
|
|
|
840
858
|
scorelUserRoot = (homeDir) => join4(homeDir, ".scorel");
|
|
841
859
|
scorelUserConfigPath = (homeDir) => join4(scorelUserRoot(homeDir), "config.toml");
|
|
842
860
|
scorelSessionsDir = (homeDir) => join4(scorelUserRoot(homeDir), "sessions");
|
|
843
|
-
scorelProjectConfigPath = (cwd) => join4(cwd, ".scorel", "config.toml");
|
|
844
861
|
loadScorelConfig = async (options) => {
|
|
845
862
|
const env = options.env ?? process.env;
|
|
846
863
|
const raw = parseToml(await readConfigText(options));
|
|
@@ -854,6 +871,7 @@ var init_config = __esm({
|
|
|
854
871
|
models,
|
|
855
872
|
modelProfile: { roles },
|
|
856
873
|
memory: loadMemory(raw),
|
|
874
|
+
runtime: loadRuntime(raw),
|
|
857
875
|
extensions: loadExtensions(raw)
|
|
858
876
|
};
|
|
859
877
|
};
|
|
@@ -870,6 +888,7 @@ var init_config = __esm({
|
|
|
870
888
|
models,
|
|
871
889
|
modelProfile: { roles },
|
|
872
890
|
memory: loadMemory(raw),
|
|
891
|
+
runtime: loadRuntime(raw),
|
|
873
892
|
extensions: loadExtensions(raw)
|
|
874
893
|
};
|
|
875
894
|
};
|
|
@@ -974,6 +993,9 @@ var init_config = __esm({
|
|
|
974
993
|
};
|
|
975
994
|
renderModelProfileConfig = (input) => {
|
|
976
995
|
const raw = parseEditableConfig(input.existingConfigText);
|
|
996
|
+
if (input.removeProviderId) {
|
|
997
|
+
removeProvider(raw, requireIdentifier(input.removeProviderId, "removeProviderId"));
|
|
998
|
+
}
|
|
977
999
|
if (input.providerType || input.provider || input.apiKeyEnv || input.apiKey || input.api || input.baseUrl) {
|
|
978
1000
|
const providerId = requireIdentifier(input.providerId, "providerId");
|
|
979
1001
|
const providerType = requireProviderType(input.providerType, "providerType");
|
|
@@ -1081,6 +1103,34 @@ var init_config = __esm({
|
|
|
1081
1103
|
}
|
|
1082
1104
|
return renderRawConfig(raw);
|
|
1083
1105
|
};
|
|
1106
|
+
removeProvider = (raw, providerId) => {
|
|
1107
|
+
delete raw.providers[providerId];
|
|
1108
|
+
const removedProviderModels = /* @__PURE__ */ new Set();
|
|
1109
|
+
for (const [providerModelId, providerModel] of Object.entries(raw.providerModels)) {
|
|
1110
|
+
if (providerModel.provider === providerId) {
|
|
1111
|
+
delete raw.providerModels[providerModelId];
|
|
1112
|
+
removedProviderModels.add(providerModelId);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
const removedAvailableModels = /* @__PURE__ */ new Set();
|
|
1116
|
+
for (const [availableModelId, availableModel] of Object.entries(raw.availableModels)) {
|
|
1117
|
+
if (availableModel.model && removedProviderModels.has(availableModel.model)) {
|
|
1118
|
+
delete raw.availableModels[availableModelId];
|
|
1119
|
+
removedAvailableModels.add(availableModelId);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
if (!raw.modelProfile?.roles) return;
|
|
1123
|
+
const fallbackModelId = Object.keys(raw.availableModels).sort()[0];
|
|
1124
|
+
if (!fallbackModelId) {
|
|
1125
|
+
delete raw.modelProfile;
|
|
1126
|
+
return;
|
|
1127
|
+
}
|
|
1128
|
+
for (const role of ["primary", "standard", "auxiliary"]) {
|
|
1129
|
+
if (!raw.modelProfile.roles[role] || removedAvailableModels.has(raw.modelProfile.roles[role])) {
|
|
1130
|
+
raw.modelProfile.roles[role] = fallbackModelId;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1084
1134
|
renderMemoryConfig = (input) => {
|
|
1085
1135
|
const raw = parseEditableConfig(input.existingConfigText);
|
|
1086
1136
|
raw.memory = {
|
|
@@ -1095,6 +1145,14 @@ var init_config = __esm({
|
|
|
1095
1145
|
};
|
|
1096
1146
|
return renderRawConfig(raw);
|
|
1097
1147
|
};
|
|
1148
|
+
renderRuntimeConfig = (input) => {
|
|
1149
|
+
const raw = parseEditableConfig(input.existingConfigText);
|
|
1150
|
+
raw.runtime = {
|
|
1151
|
+
...loadRuntime(raw),
|
|
1152
|
+
...input.tokenSavingRtk !== void 0 ? { tokenSavingRtk: requireBoolean(input.tokenSavingRtk, "runtime.tokenSavingRtk") } : {}
|
|
1153
|
+
};
|
|
1154
|
+
return renderRawConfig(raw);
|
|
1155
|
+
};
|
|
1098
1156
|
renderExtensionConfig = (input) => {
|
|
1099
1157
|
const raw = parseEditableConfig(input.existingConfigText);
|
|
1100
1158
|
const extensionId = requireIdentifier(input.extensionId, "extensionId");
|
|
@@ -1126,6 +1184,9 @@ var init_config = __esm({
|
|
|
1126
1184
|
dreamIdleMinutes: 60,
|
|
1127
1185
|
autoCompactThreshold: 0.8
|
|
1128
1186
|
};
|
|
1187
|
+
DEFAULT_RUNTIME_CONFIG = {
|
|
1188
|
+
tokenSavingRtk: false
|
|
1189
|
+
};
|
|
1129
1190
|
loadMemory = (raw) => ({
|
|
1130
1191
|
enabled: raw.memory?.enabled ?? DEFAULT_MEMORY_CONFIG.enabled,
|
|
1131
1192
|
daily: raw.memory?.daily ?? DEFAULT_MEMORY_CONFIG.daily,
|
|
@@ -1135,6 +1196,9 @@ var init_config = __esm({
|
|
|
1135
1196
|
dreamIdleMinutes: requireNonNegativeNumber(raw.memory?.dreamIdleMinutes ?? DEFAULT_MEMORY_CONFIG.dreamIdleMinutes, "memory.dreamIdleMinutes"),
|
|
1136
1197
|
autoCompactThreshold: requireCompactThreshold(raw.memory?.autoCompactThreshold ?? DEFAULT_MEMORY_CONFIG.autoCompactThreshold)
|
|
1137
1198
|
});
|
|
1199
|
+
loadRuntime = (raw) => ({
|
|
1200
|
+
tokenSavingRtk: raw.runtime?.tokenSavingRtk ?? DEFAULT_RUNTIME_CONFIG.tokenSavingRtk
|
|
1201
|
+
});
|
|
1138
1202
|
loadExtensions = (raw) => {
|
|
1139
1203
|
const extensions = {};
|
|
1140
1204
|
for (const [extensionId, extension] of Object.entries(raw.extensions)) {
|
|
@@ -1297,22 +1361,26 @@ var init_config = __esm({
|
|
|
1297
1361
|
};
|
|
1298
1362
|
};
|
|
1299
1363
|
readConfigText = async (options) => {
|
|
1300
|
-
const
|
|
1364
|
+
const userPath = configPathForDevice(options);
|
|
1301
1365
|
try {
|
|
1302
|
-
return await readFile3(
|
|
1303
|
-
} catch {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
throw new Error(`Scorel config not found: ${projectPath}`);
|
|
1307
|
-
}
|
|
1308
|
-
const userPath = scorelUserConfigPath(home);
|
|
1309
|
-
try {
|
|
1310
|
-
return await readFile3(userPath, "utf8");
|
|
1311
|
-
} catch {
|
|
1312
|
-
throw new Error(`Scorel config not found: ${projectPath} or ${userPath}`);
|
|
1366
|
+
return await readFile3(userPath, "utf8");
|
|
1367
|
+
} catch (cause) {
|
|
1368
|
+
if (isNodeErrorCode(cause, "ENOENT")) {
|
|
1369
|
+
throw new Error(`Scorel config not found: ${userPath}`);
|
|
1313
1370
|
}
|
|
1371
|
+
throw cause;
|
|
1314
1372
|
}
|
|
1315
1373
|
};
|
|
1374
|
+
configPathForDevice = (options) => {
|
|
1375
|
+
if (options.scorelHomeDir) {
|
|
1376
|
+
return join4(options.scorelHomeDir, "config.toml");
|
|
1377
|
+
}
|
|
1378
|
+
const home = options.homeDir ?? process.env.HOME;
|
|
1379
|
+
if (!home) {
|
|
1380
|
+
throw new Error("Scorel config not found: HOME is not set");
|
|
1381
|
+
}
|
|
1382
|
+
return scorelUserConfigPath(home);
|
|
1383
|
+
};
|
|
1316
1384
|
parseToml = (text) => {
|
|
1317
1385
|
const result = emptyRawConfig();
|
|
1318
1386
|
let section2 = { kind: "root" };
|
|
@@ -1414,6 +1482,12 @@ var init_config = __esm({
|
|
|
1414
1482
|
lines.push(`autoCompactThreshold = ${memory.autoCompactThreshold}`);
|
|
1415
1483
|
lines.push("");
|
|
1416
1484
|
}
|
|
1485
|
+
if (raw.runtime) {
|
|
1486
|
+
const runtime = loadRuntime(raw);
|
|
1487
|
+
lines.push("[runtime]");
|
|
1488
|
+
lines.push(`tokenSavingRtk = ${runtime.tokenSavingRtk}`);
|
|
1489
|
+
lines.push("");
|
|
1490
|
+
}
|
|
1417
1491
|
for (const [extensionId, extension] of Object.entries(raw.extensions).sort(([left], [right]) => left.localeCompare(right))) {
|
|
1418
1492
|
lines.push(`[extensions.${extensionId}]`);
|
|
1419
1493
|
lines.push(`enabled = ${extension.enabled === true}`);
|
|
@@ -1545,6 +1619,9 @@ var init_config = __esm({
|
|
|
1545
1619
|
if (section2 === "memory") {
|
|
1546
1620
|
return { kind: "memory" };
|
|
1547
1621
|
}
|
|
1622
|
+
if (section2 === "runtime") {
|
|
1623
|
+
return { kind: "runtime" };
|
|
1624
|
+
}
|
|
1548
1625
|
const extensionConfigMatch = /^extensions\.([A-Za-z0-9_-]+)\.config$/.exec(section2);
|
|
1549
1626
|
if (extensionConfigMatch?.[1]) {
|
|
1550
1627
|
return { kind: "extensionConfig", id: extensionConfigMatch[1] };
|
|
@@ -1567,6 +1644,8 @@ var init_config = __esm({
|
|
|
1567
1644
|
config.modelProfile.roles ??= {};
|
|
1568
1645
|
} else if (section2.kind === "memory") {
|
|
1569
1646
|
config.memory ??= {};
|
|
1647
|
+
} else if (section2.kind === "runtime") {
|
|
1648
|
+
config.runtime ??= {};
|
|
1570
1649
|
} else if (section2.kind === "extension") {
|
|
1571
1650
|
config.extensions[section2.id] ??= {};
|
|
1572
1651
|
} else if (section2.kind === "extensionConfig") {
|
|
@@ -1592,6 +1671,9 @@ var init_config = __esm({
|
|
|
1592
1671
|
} else if (section2.kind === "memory") {
|
|
1593
1672
|
config.memory ??= {};
|
|
1594
1673
|
setValue(config.memory, key, value);
|
|
1674
|
+
} else if (section2.kind === "runtime") {
|
|
1675
|
+
config.runtime ??= {};
|
|
1676
|
+
setValue(config.runtime, key, value);
|
|
1595
1677
|
} else if (section2.kind === "extension") {
|
|
1596
1678
|
config.extensions[section2.id] ??= {};
|
|
1597
1679
|
setValue(config.extensions[section2.id], key, value);
|
|
@@ -1645,6 +1727,7 @@ var init_config = __esm({
|
|
|
1645
1727
|
};
|
|
1646
1728
|
tomlString = (value) => `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
1647
1729
|
renderTomlValue = (value) => typeof value === "string" ? tomlString(value) : String(value);
|
|
1730
|
+
isNodeErrorCode = (cause, code) => typeof cause === "object" && cause !== null && "code" in cause && cause.code === code;
|
|
1648
1731
|
requireModelRole = (value, role, models) => {
|
|
1649
1732
|
const modelId = requireString(value, `model_profile.roles.${role}`);
|
|
1650
1733
|
if (!models[modelId]) {
|
|
@@ -1660,9 +1743,10 @@ var init_config = __esm({
|
|
|
1660
1743
|
import { createHash, randomUUID as randomUUID2 } from "node:crypto";
|
|
1661
1744
|
import { execFile } from "node:child_process";
|
|
1662
1745
|
import { mkdir as mkdir2, readFile as readFile4, rename as rename2, rm, stat as stat3, writeFile as writeFile2 } from "node:fs/promises";
|
|
1663
|
-
import {
|
|
1746
|
+
import { userInfo } from "node:os";
|
|
1747
|
+
import { basename as basename2, dirname as dirname3, extname, isAbsolute, relative, resolve } from "node:path";
|
|
1664
1748
|
import { promisify } from "node:util";
|
|
1665
|
-
var execFileAsync, DEFAULT_SEARCH_LIMIT, DEFAULT_GREP_LIMIT, DEFAULT_READ_LIMIT, DEFAULT_CONTEXT_WINDOW, READ_TOKEN_BUDGET_RATIO, FULL_READ_TOKEN_BUDGET_RATIO, createCodingTools, parseReadArgs, parseWriteArgs, parseEditArgs, parseBashArgs, parseGlobArgs, parseGrepArgs, parseTodoWriteArgs, parseTodoItem, expectRecord, expectPath, expectString, optionalString, optionalNumber, optionalBoolean, snapshotFile, sameSnapshot, exists, isWithin, linesOf, IMAGE_EXTENSIONS, DOCUMENT_EXTENSIONS, BINARY_EXTENSIONS, assertReadableFileKind, assertTextBuffer, selectCompleteLinesWithinBudget, estimateTokens, renderReadLines, readTokenBudget, completeRanges, hasCompleteCoverage, mergeRanges, countOccurrences, atomicWriteFile, bashResult, truncate, textResult, byteLength, isTimeoutError, isExecError, runRipgrep, splitOutput, vcsExcludes, grepArgs, splitGlobPatterns, paginate, toWorkspaceRelative, relativizeGrepLine, relativizeCountLine, sortPathsByMtime, formatPaginatedText, formatLimitSuffix, parseCountLines;
|
|
1749
|
+
var execFileAsync, DEFAULT_SEARCH_LIMIT, DEFAULT_GREP_LIMIT, DEFAULT_READ_LIMIT, DEFAULT_CONTEXT_WINDOW, READ_TOKEN_BUDGET_RATIO, FULL_READ_TOKEN_BUDGET_RATIO, createCodingTools, parseReadArgs, parseWriteArgs, parseEditArgs, parseBashArgs, parseGlobArgs, parseGrepArgs, parseTodoWriteArgs, parseTodoItem, expectRecord, expectPath, expectString, optionalString, optionalNumber, optionalBoolean, snapshotFile, sameSnapshot, exists, isWithin, linesOf, IMAGE_EXTENSIONS, DOCUMENT_EXTENSIONS, BINARY_EXTENSIONS, assertReadableFileKind, assertTextBuffer, selectCompleteLinesWithinBudget, estimateTokens, renderReadLines, readTokenBudget, completeRanges, hasCompleteCoverage, mergeRanges, countOccurrences, atomicWriteFile, bashResult, resolveDefaultShell, resolveRtkCommand, rtkRewriteResult, executableRewriteCommand, readRtkGain, rtkSavedTokenDelta, withRtkSavings, nonNegativeInteger, isRecord3, shellQuote, shellCommandArgs, userShell, truncate, textResult, byteLength, isTimeoutError, isExecError, runRipgrep, splitOutput, vcsExcludes, grepArgs, splitGlobPatterns, paginate, toWorkspaceRelative, relativizeGrepLine, relativizeCountLine, sortPathsByMtime, formatPaginatedText, formatLimitSuffix, parseCountLines;
|
|
1666
1750
|
var init_coding_tools = __esm({
|
|
1667
1751
|
"packages/core/src/tools/coding-tools.ts"() {
|
|
1668
1752
|
"use strict";
|
|
@@ -1682,6 +1766,7 @@ var init_coding_tools = __esm({
|
|
|
1682
1766
|
const maxOutputBytes = options.maxOutputBytes ?? 16e3;
|
|
1683
1767
|
const normalReadTokens = options.maxReadTokens ?? readTokenBudget(options.contextWindow, READ_TOKEN_BUDGET_RATIO);
|
|
1684
1768
|
const fullReadTokens = options.maxReadTokens ?? readTokenBudget(options.contextWindow, FULL_READ_TOKEN_BUDGET_RATIO);
|
|
1769
|
+
const defaultShell = resolveDefaultShell(options.defaultShell);
|
|
1685
1770
|
const resolveWorkspacePath = (input) => {
|
|
1686
1771
|
if (input.length === 0) {
|
|
1687
1772
|
throw new Error("path must not be empty");
|
|
@@ -1834,25 +1919,52 @@ String: ${input.old_string}`
|
|
|
1834
1919
|
const commandCwd = input.cwd ? resolveWorkspacePath(input.cwd) : root;
|
|
1835
1920
|
const timeoutMs = Math.min(input.timeoutMs ?? defaultTimeoutMs, maxTimeoutMs);
|
|
1836
1921
|
const outputLimit = input.maxOutputBytes ?? maxOutputBytes;
|
|
1922
|
+
const rtk = options.tokenSaving?.rtk;
|
|
1923
|
+
const rtkCommand = await resolveRtkCommand(rtk, input.command);
|
|
1924
|
+
const command = rtkCommand.rewrittenCommand ?? input.command;
|
|
1925
|
+
const executionCommand = rtkCommand.executionCommand ?? input.command;
|
|
1926
|
+
const executable = defaultShell;
|
|
1927
|
+
const argv = shellCommandArgs(defaultShell, executionCommand);
|
|
1928
|
+
const rtkGainBefore = rtkCommand.applied && rtk?.executable ? await readRtkGain(rtk.executable, commandCwd) : void 0;
|
|
1929
|
+
const rtkResult = {
|
|
1930
|
+
enabled: rtk?.enabled === true,
|
|
1931
|
+
applied: rtkCommand.applied,
|
|
1932
|
+
...rtk?.executable ? { executable: rtk.executable } : {},
|
|
1933
|
+
...rtkCommand.rewrittenCommand ? { rewrittenCommand: rtkCommand.rewrittenCommand } : {}
|
|
1934
|
+
};
|
|
1837
1935
|
try {
|
|
1838
|
-
const result = await execFileAsync(
|
|
1936
|
+
const result = await execFileAsync(executable, argv, {
|
|
1839
1937
|
cwd: commandCwd,
|
|
1840
1938
|
timeout: timeoutMs,
|
|
1841
1939
|
signal,
|
|
1842
1940
|
maxBuffer: Math.max(outputLimit * 4, 1024 * 1024)
|
|
1843
1941
|
});
|
|
1844
|
-
|
|
1942
|
+
const rtkSavedTokens = rtk?.executable ? await rtkSavedTokenDelta(rtk.executable, commandCwd, rtkGainBefore) : void 0;
|
|
1943
|
+
return bashResult({
|
|
1944
|
+
exitCode: 0,
|
|
1945
|
+
stdout: result.stdout,
|
|
1946
|
+
stderr: result.stderr,
|
|
1947
|
+
cwd: commandCwd,
|
|
1948
|
+
outputLimit,
|
|
1949
|
+
shell: defaultShell,
|
|
1950
|
+
command,
|
|
1951
|
+
rtk: withRtkSavings(rtkResult, rtkSavedTokens)
|
|
1952
|
+
});
|
|
1845
1953
|
} catch (cause) {
|
|
1846
1954
|
if (isTimeoutError(cause)) {
|
|
1847
1955
|
throw new Error(`Bash command timed out after ${timeoutMs}ms`);
|
|
1848
1956
|
}
|
|
1849
1957
|
if (isExecError(cause)) {
|
|
1958
|
+
const rtkSavedTokens = rtk?.executable ? await rtkSavedTokenDelta(rtk.executable, commandCwd, rtkGainBefore) : void 0;
|
|
1850
1959
|
return bashResult({
|
|
1851
1960
|
exitCode: typeof cause.code === "number" ? cause.code : 1,
|
|
1852
1961
|
stdout: String(cause.stdout ?? ""),
|
|
1853
1962
|
stderr: String(cause.stderr ?? cause.message),
|
|
1854
1963
|
cwd: commandCwd,
|
|
1855
|
-
outputLimit
|
|
1964
|
+
outputLimit,
|
|
1965
|
+
shell: defaultShell,
|
|
1966
|
+
command,
|
|
1967
|
+
rtk: withRtkSavings(rtkResult, rtkSavedTokens)
|
|
1856
1968
|
});
|
|
1857
1969
|
}
|
|
1858
1970
|
throw cause;
|
|
@@ -1866,7 +1978,7 @@ String: ${input.old_string}`
|
|
|
1866
1978
|
const input = parseGlobArgs(args);
|
|
1867
1979
|
const limit = input.head_limit ?? DEFAULT_SEARCH_LIMIT;
|
|
1868
1980
|
const offset = input.offset ?? 0;
|
|
1869
|
-
const all = await runRipgrep(["--files", "--hidden", "--glob", input.pattern, ...vcsExcludes()], workspaceTarget(input.path), root, signal);
|
|
1981
|
+
const all = (await runRipgrep(["--files", "--hidden", "--glob", input.pattern, ...vcsExcludes()], workspaceTarget(input.path), root, signal)).sort((left, right) => toWorkspaceRelative(root)(left).localeCompare(toWorkspaceRelative(root)(right)));
|
|
1870
1982
|
const selected = paginate(all, limit, offset);
|
|
1871
1983
|
const text = selected.items.map(toWorkspaceRelative(root)).join("\n");
|
|
1872
1984
|
return textResult(text || "No files found", {
|
|
@@ -2227,9 +2339,96 @@ ${stdout}
|
|
|
2227
2339
|
stderr:
|
|
2228
2340
|
${stderr}`, {
|
|
2229
2341
|
exitCode: input.exitCode,
|
|
2230
|
-
cwd: input.cwd
|
|
2342
|
+
cwd: input.cwd,
|
|
2343
|
+
...input.shell ? { shell: input.shell } : {},
|
|
2344
|
+
...input.command ? { command: input.command } : {},
|
|
2345
|
+
...input.rtk ? {
|
|
2346
|
+
rtk: {
|
|
2347
|
+
...input.rtk,
|
|
2348
|
+
estimatedOutputTokens: estimateTokens(`${stdout}
|
|
2349
|
+
${stderr}`)
|
|
2350
|
+
}
|
|
2351
|
+
} : {}
|
|
2231
2352
|
});
|
|
2232
2353
|
};
|
|
2354
|
+
resolveDefaultShell = (input) => {
|
|
2355
|
+
const shell = input || process.env.SHELL || userShell() || "/bin/sh";
|
|
2356
|
+
return shell.trim() || "/bin/sh";
|
|
2357
|
+
};
|
|
2358
|
+
resolveRtkCommand = async (rtk, command) => {
|
|
2359
|
+
if (rtk?.enabled !== true || typeof rtk.executable !== "string" || rtk.executable.length === 0) {
|
|
2360
|
+
return { applied: false };
|
|
2361
|
+
}
|
|
2362
|
+
try {
|
|
2363
|
+
const result = await execFileAsync(rtk.executable, ["rewrite", command], {
|
|
2364
|
+
timeout: 5e3,
|
|
2365
|
+
maxBuffer: 1024 * 1024
|
|
2366
|
+
});
|
|
2367
|
+
return rtkRewriteResult(result.stdout, rtk.executable);
|
|
2368
|
+
} catch (cause) {
|
|
2369
|
+
if (isExecError(cause) && typeof cause.stdout === "string") {
|
|
2370
|
+
return rtkRewriteResult(cause.stdout, rtk.executable);
|
|
2371
|
+
}
|
|
2372
|
+
return { applied: false };
|
|
2373
|
+
}
|
|
2374
|
+
};
|
|
2375
|
+
rtkRewriteResult = (stdout, executable) => {
|
|
2376
|
+
const rewrittenCommand = stdout.trim();
|
|
2377
|
+
return rewrittenCommand ? { applied: true, rewrittenCommand, executionCommand: executableRewriteCommand(rewrittenCommand, executable) } : { applied: false };
|
|
2378
|
+
};
|
|
2379
|
+
executableRewriteCommand = (command, executable) => command.replace(/^rtk(?=\s|$)/, shellQuote(executable));
|
|
2380
|
+
readRtkGain = async (rtkExecutable, cwd) => {
|
|
2381
|
+
try {
|
|
2382
|
+
const { stdout } = await execFileAsync(rtkExecutable, ["gain", "--project", "--format", "json"], {
|
|
2383
|
+
cwd,
|
|
2384
|
+
timeout: 5e3,
|
|
2385
|
+
maxBuffer: 5e6
|
|
2386
|
+
});
|
|
2387
|
+
const parsed = JSON.parse(stdout);
|
|
2388
|
+
if (!isRecord3(parsed) || !isRecord3(parsed.summary)) {
|
|
2389
|
+
return void 0;
|
|
2390
|
+
}
|
|
2391
|
+
return { savedTokens: nonNegativeInteger(parsed.summary.total_saved) };
|
|
2392
|
+
} catch {
|
|
2393
|
+
return void 0;
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
rtkSavedTokenDelta = async (rtkExecutable, cwd, before) => {
|
|
2397
|
+
if (!before) {
|
|
2398
|
+
return void 0;
|
|
2399
|
+
}
|
|
2400
|
+
const after = await readRtkGain(rtkExecutable, cwd);
|
|
2401
|
+
if (!after) {
|
|
2402
|
+
return void 0;
|
|
2403
|
+
}
|
|
2404
|
+
return Math.max(0, after.savedTokens - before.savedTokens);
|
|
2405
|
+
};
|
|
2406
|
+
withRtkSavings = (rtk, savedTokens) => ({
|
|
2407
|
+
...rtk,
|
|
2408
|
+
...rtk.applied && savedTokens !== void 0 ? { estimatedSavedTokens: savedTokens } : {}
|
|
2409
|
+
});
|
|
2410
|
+
nonNegativeInteger = (value) => {
|
|
2411
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
2412
|
+
return 0;
|
|
2413
|
+
}
|
|
2414
|
+
return Math.floor(value);
|
|
2415
|
+
};
|
|
2416
|
+
isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2417
|
+
shellQuote = (value) => `'${value.replace(/'/g, "'\\''")}'`;
|
|
2418
|
+
shellCommandArgs = (shell, command) => {
|
|
2419
|
+
const name = basename2(shell).toLowerCase();
|
|
2420
|
+
if (name === "csh" || name === "tcsh" || name === "fish") {
|
|
2421
|
+
return ["-c", command];
|
|
2422
|
+
}
|
|
2423
|
+
return ["-lc", command];
|
|
2424
|
+
};
|
|
2425
|
+
userShell = () => {
|
|
2426
|
+
try {
|
|
2427
|
+
return userInfo().shell ?? void 0;
|
|
2428
|
+
} catch {
|
|
2429
|
+
return void 0;
|
|
2430
|
+
}
|
|
2431
|
+
};
|
|
2233
2432
|
truncate = (value, maxBytes, label) => {
|
|
2234
2433
|
const bytes = Buffer.byteLength(value);
|
|
2235
2434
|
if (bytes <= maxBytes) {
|
|
@@ -2413,7 +2612,7 @@ var init_tools = __esm({
|
|
|
2413
2612
|
});
|
|
2414
2613
|
|
|
2415
2614
|
// packages/core/src/channel/index.ts
|
|
2416
|
-
var createSendChannelMessageTool, parseSendChannelMessageInput,
|
|
2615
|
+
var createSendChannelMessageTool, parseSendChannelMessageInput, parseAttachments, optionalString2, isRecord4;
|
|
2417
2616
|
var init_channel = __esm({
|
|
2418
2617
|
"packages/core/src/channel/index.ts"() {
|
|
2419
2618
|
"use strict";
|
|
@@ -2426,16 +2625,18 @@ var init_channel = __esm({
|
|
|
2426
2625
|
const result = await options.sendCurrent(input);
|
|
2427
2626
|
return {
|
|
2428
2627
|
content: [{ type: "text", text: `Channel message sent to ${result.channel}:${result.target}` }],
|
|
2429
|
-
details: result
|
|
2628
|
+
details: { ...result, attachments: result.attachments ?? input.attachments?.length ?? 0 }
|
|
2430
2629
|
};
|
|
2431
2630
|
}
|
|
2432
2631
|
});
|
|
2433
2632
|
parseSendChannelMessageInput = (value) => {
|
|
2434
|
-
if (!
|
|
2633
|
+
if (!isRecord4(value)) {
|
|
2435
2634
|
throw new Error("SendChannelMessage args must be an object");
|
|
2436
2635
|
}
|
|
2437
|
-
|
|
2438
|
-
|
|
2636
|
+
const text = typeof value.text === "string" && value.text.trim().length > 0 ? value.text : void 0;
|
|
2637
|
+
const attachments = parseAttachments(value.attachments);
|
|
2638
|
+
if (!text && attachments.length === 0) {
|
|
2639
|
+
throw new Error("SendChannelMessage requires text or attachments");
|
|
2439
2640
|
}
|
|
2440
2641
|
if (value.channel !== void 0 && (typeof value.channel !== "string" || value.channel.trim().length === 0)) {
|
|
2441
2642
|
throw new Error("SendChannelMessage.channel must be a non-empty string when provided");
|
|
@@ -2444,19 +2645,57 @@ var init_channel = __esm({
|
|
|
2444
2645
|
throw new Error("SendChannelMessage.target must be current when provided");
|
|
2445
2646
|
}
|
|
2446
2647
|
return {
|
|
2447
|
-
text:
|
|
2648
|
+
...text ? { text } : {},
|
|
2649
|
+
...attachments.length > 0 ? { attachments } : {},
|
|
2448
2650
|
...typeof value.channel === "string" ? { channel: value.channel } : {},
|
|
2449
2651
|
...value.target === "current" ? { target: "current" } : {}
|
|
2450
2652
|
};
|
|
2451
2653
|
};
|
|
2452
|
-
|
|
2654
|
+
parseAttachments = (value) => {
|
|
2655
|
+
if (value === void 0) {
|
|
2656
|
+
return [];
|
|
2657
|
+
}
|
|
2658
|
+
if (!Array.isArray(value)) {
|
|
2659
|
+
throw new Error("SendChannelMessage.attachments must be an array");
|
|
2660
|
+
}
|
|
2661
|
+
return value.map((item, index) => {
|
|
2662
|
+
if (!isRecord4(item)) {
|
|
2663
|
+
throw new Error(`SendChannelMessage.attachments.${index} must be an object`);
|
|
2664
|
+
}
|
|
2665
|
+
if (item.type !== "image" && item.type !== "file") {
|
|
2666
|
+
throw new Error(`SendChannelMessage.attachments.${index}.type must be image or file`);
|
|
2667
|
+
}
|
|
2668
|
+
const path = optionalString2(item.path, `SendChannelMessage.attachments.${index}.path`);
|
|
2669
|
+
const url = optionalString2(item.url, `SendChannelMessage.attachments.${index}.url`);
|
|
2670
|
+
if (!path && !url) {
|
|
2671
|
+
throw new Error(`SendChannelMessage.attachments.${index} requires path or url`);
|
|
2672
|
+
}
|
|
2673
|
+
return {
|
|
2674
|
+
type: item.type,
|
|
2675
|
+
...path ? { path } : {},
|
|
2676
|
+
...url ? { url } : {},
|
|
2677
|
+
...optionalString2(item.mimeType, `SendChannelMessage.attachments.${index}.mimeType`) ? { mimeType: optionalString2(item.mimeType, `SendChannelMessage.attachments.${index}.mimeType`) } : {},
|
|
2678
|
+
...optionalString2(item.caption, `SendChannelMessage.attachments.${index}.caption`) ? { caption: optionalString2(item.caption, `SendChannelMessage.attachments.${index}.caption`) } : {}
|
|
2679
|
+
};
|
|
2680
|
+
});
|
|
2681
|
+
};
|
|
2682
|
+
optionalString2 = (value, name) => {
|
|
2683
|
+
if (value === void 0 || value === "") {
|
|
2684
|
+
return void 0;
|
|
2685
|
+
}
|
|
2686
|
+
if (typeof value !== "string") {
|
|
2687
|
+
throw new Error(`${name} must be a string`);
|
|
2688
|
+
}
|
|
2689
|
+
return value;
|
|
2690
|
+
};
|
|
2691
|
+
isRecord4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2453
2692
|
}
|
|
2454
2693
|
});
|
|
2455
2694
|
|
|
2456
2695
|
// packages/core/src/extensions/index.ts
|
|
2457
2696
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
2458
2697
|
import { dirname as dirname4, resolve as resolve2 } from "node:path";
|
|
2459
|
-
var loadExtensionManifest, parseExtensionManifest, requireString2, requireIdentifier2, requireKind, requireRelativePath, optionalRelativePaths,
|
|
2698
|
+
var loadExtensionManifest, parseExtensionManifest, requireString2, requireIdentifier2, requireKind, requireRelativePath, optionalRelativePaths, isRecord5;
|
|
2460
2699
|
var init_extensions = __esm({
|
|
2461
2700
|
"packages/core/src/extensions/index.ts"() {
|
|
2462
2701
|
"use strict";
|
|
@@ -2469,7 +2708,7 @@ var init_extensions = __esm({
|
|
|
2469
2708
|
const message = cause instanceof Error ? cause.message : String(cause);
|
|
2470
2709
|
throw new Error(`Invalid extension manifest JSON at ${manifestPath}: ${message}`);
|
|
2471
2710
|
}
|
|
2472
|
-
if (!
|
|
2711
|
+
if (!isRecord5(value)) {
|
|
2473
2712
|
throw new Error(`Extension manifest at ${manifestPath} must be an object`);
|
|
2474
2713
|
}
|
|
2475
2714
|
const rootDir = dirname4(resolve2(manifestPath));
|
|
@@ -2525,7 +2764,7 @@ var init_extensions = __esm({
|
|
|
2525
2764
|
}
|
|
2526
2765
|
return value.map((item, index) => requireRelativePath(item, `${name}.${index}`, manifestPath));
|
|
2527
2766
|
};
|
|
2528
|
-
|
|
2767
|
+
isRecord5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2529
2768
|
}
|
|
2530
2769
|
});
|
|
2531
2770
|
|
|
@@ -2534,7 +2773,7 @@ import { existsSync } from "node:fs";
|
|
|
2534
2773
|
import { readdir as readdir4, readFile as readFile6 } from "node:fs/promises";
|
|
2535
2774
|
import { homedir as homedir2, platform, release } from "node:os";
|
|
2536
2775
|
import { dirname as dirname5, join as join5, resolve as resolve3 } from "node:path";
|
|
2537
|
-
var BASELINE_PROMPT, buildInstructionSnapshot, renderSystemPrompt, section, discoverAgentsSources, projectAgentsPaths, findGitRoot, renderAgentsBlock, renderWorkspaceBlock, renderEnvironmentBlock, renderTimeBlock,
|
|
2776
|
+
var BASELINE_PROMPT, buildInstructionSnapshot, renderSystemPrompt, section, discoverAgentsSources, projectAgentsPaths, findGitRoot, renderAgentsBlock, renderWorkspaceBlock, renderEnvironmentBlock, renderTimeBlock, isNodeErrorCode2;
|
|
2538
2777
|
var init_instructions = __esm({
|
|
2539
2778
|
"packages/core/src/instructions/index.ts"() {
|
|
2540
2779
|
"use strict";
|
|
@@ -2598,7 +2837,7 @@ var init_instructions = __esm({
|
|
|
2598
2837
|
content
|
|
2599
2838
|
});
|
|
2600
2839
|
} catch (cause) {
|
|
2601
|
-
if (!
|
|
2840
|
+
if (!isNodeErrorCode2(cause, "ENOENT") && !isNodeErrorCode2(cause, "ENOTDIR")) {
|
|
2602
2841
|
throw cause;
|
|
2603
2842
|
}
|
|
2604
2843
|
}
|
|
@@ -2661,7 +2900,7 @@ var init_instructions = __esm({
|
|
|
2661
2900
|
};
|
|
2662
2901
|
renderEnvironmentBlock = (env) => [`Platform: ${platform()} ${release()}`, `Shell: ${env.SHELL ?? "unknown"}`].join("\n");
|
|
2663
2902
|
renderTimeBlock = (timestamp) => [`Session started at: ${new Date(timestamp).toISOString()}`, `Timezone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`].join("\n");
|
|
2664
|
-
|
|
2903
|
+
isNodeErrorCode2 = (cause, code) => cause instanceof Error && "code" in cause && cause.code === code;
|
|
2665
2904
|
}
|
|
2666
2905
|
});
|
|
2667
2906
|
|
|
@@ -2669,7 +2908,7 @@ var init_instructions = __esm({
|
|
|
2669
2908
|
import { appendFile, mkdir as mkdir3, readFile as readFile7, writeFile as writeFile3 } from "node:fs/promises";
|
|
2670
2909
|
import { homedir as homedir3 } from "node:os";
|
|
2671
2910
|
import { join as join6 } from "node:path";
|
|
2672
|
-
var memoryDate, scorelMemoryPaths, scorelSessionMemoryPaths, buildMemoryContext, renderMemoryHarness, appendDailyEntry, createAppendDailyTool, renderDailyEntry, readSessionMemory, writeSessionMemory, renderSessionMemory, ensureMemoryFiles, ensureFile, readOptional, trimForContext, compactLine, renderList, renderBullets, normalizeMarkdownFile, parseAppendDailyInput, requireString3, optionalStringArray,
|
|
2911
|
+
var memoryDate, scorelMemoryPaths, scorelSessionMemoryPaths, buildMemoryContext, renderMemoryHarness, appendDailyEntry, createAppendDailyTool, renderDailyEntry, readMemoryDreamState, writeMemoryDreamState, readSessionMemory, writeSessionMemory, renderSessionMemory, ensureMemoryFiles, ensureFile, readOptional, trimForContext, compactLine, renderList, renderBullets, normalizeMarkdownFile, parseAppendDailyInput, validateAppendDailyInput, isLowSignalSummary, containsNormalizedDailyEntry, normalizeDailyText, requireString3, optionalStringArray, optionalNumber2, optionalString3, parseLastFailure, isRecord6, safeProjectId, isNodeErrorCode3;
|
|
2673
2912
|
var init_memory = __esm({
|
|
2674
2913
|
"packages/core/src/memory/index.ts"() {
|
|
2675
2914
|
"use strict";
|
|
@@ -2739,7 +2978,11 @@ var init_memory = __esm({
|
|
|
2739
2978
|
await ensureMemoryFiles(paths);
|
|
2740
2979
|
const text = options.text.trim();
|
|
2741
2980
|
if (!text) {
|
|
2742
|
-
return { path: paths.todayDailyPath, entry: "", date: paths.today };
|
|
2981
|
+
return { path: paths.todayDailyPath, entry: "", date: paths.today, skippedReason: "empty" };
|
|
2982
|
+
}
|
|
2983
|
+
const existing = await readOptional(paths.todayDailyPath);
|
|
2984
|
+
if (containsNormalizedDailyEntry(existing, text)) {
|
|
2985
|
+
return { path: paths.todayDailyPath, entry: "", date: paths.today, skippedReason: "duplicate" };
|
|
2743
2986
|
}
|
|
2744
2987
|
const time = new Date((options.now ?? Date.now)()).toISOString().slice(11, 16);
|
|
2745
2988
|
const entry = `- ${time} ${text.replace(/\s+/g, " ")}
|
|
@@ -2756,6 +2999,7 @@ var init_memory = __esm({
|
|
|
2756
2999
|
].join(" "),
|
|
2757
3000
|
execute: async (_toolCallId, args) => {
|
|
2758
3001
|
const input = parseAppendDailyInput(args);
|
|
3002
|
+
validateAppendDailyInput(input);
|
|
2759
3003
|
const result = await appendDailyEntry({
|
|
2760
3004
|
projectId: options.projectId,
|
|
2761
3005
|
homeDir: options.homeDir,
|
|
@@ -2766,11 +3010,12 @@ var init_memory = __esm({
|
|
|
2766
3010
|
return {
|
|
2767
3011
|
content: [{
|
|
2768
3012
|
type: "text",
|
|
2769
|
-
text: result.entry ? `Daily appended: ${result.date}` :
|
|
3013
|
+
text: result.entry ? `Daily appended: ${result.date}` : `Daily append skipped: ${result.skippedReason ?? "empty"}`
|
|
2770
3014
|
}],
|
|
2771
3015
|
details: {
|
|
2772
3016
|
path: result.path,
|
|
2773
|
-
date: result.date
|
|
3017
|
+
date: result.date,
|
|
3018
|
+
skippedReason: result.skippedReason
|
|
2774
3019
|
}
|
|
2775
3020
|
};
|
|
2776
3021
|
}
|
|
@@ -2781,10 +3026,45 @@ var init_memory = __esm({
|
|
|
2781
3026
|
renderList("Completed", input.completed),
|
|
2782
3027
|
renderList("Decisions", input.decisions),
|
|
2783
3028
|
renderList("Follow-ups", input.followUps),
|
|
2784
|
-
renderList("Memory candidates", input.memoryCandidates)
|
|
3029
|
+
renderList("Memory candidates", input.memoryCandidates),
|
|
3030
|
+
renderList("Evidence", input.evidence)
|
|
2785
3031
|
].filter(Boolean);
|
|
2786
3032
|
return sections.join(" ");
|
|
2787
3033
|
};
|
|
3034
|
+
readMemoryDreamState = async (options) => {
|
|
3035
|
+
const paths = scorelMemoryPaths(options);
|
|
3036
|
+
const text = await readOptional(paths.dreamStatePath);
|
|
3037
|
+
if (!text.trim()) return void 0;
|
|
3038
|
+
try {
|
|
3039
|
+
const parsed = JSON.parse(text);
|
|
3040
|
+
if (parsed.projectId !== options.projectId) return void 0;
|
|
3041
|
+
return {
|
|
3042
|
+
projectId: options.projectId,
|
|
3043
|
+
dirty: Boolean(parsed.dirty),
|
|
3044
|
+
running: Boolean(parsed.running),
|
|
3045
|
+
sessionId: optionalString3(parsed.sessionId),
|
|
3046
|
+
clientId: optionalString3(parsed.clientId),
|
|
3047
|
+
lastDailyAppendAt: optionalNumber2(parsed.lastDailyAppendAt),
|
|
3048
|
+
lastDailyPath: optionalString3(parsed.lastDailyPath),
|
|
3049
|
+
scheduledFor: optionalNumber2(parsed.scheduledFor),
|
|
3050
|
+
lastAttemptAt: optionalNumber2(parsed.lastAttemptAt),
|
|
3051
|
+
lastSuccessAt: optionalNumber2(parsed.lastSuccessAt),
|
|
3052
|
+
lastFailure: parseLastFailure(parsed.lastFailure),
|
|
3053
|
+
lastProjectMemoryUpdateAt: optionalNumber2(parsed.lastProjectMemoryUpdateAt),
|
|
3054
|
+
lastRootMemoryUpdateAt: optionalNumber2(parsed.lastRootMemoryUpdateAt)
|
|
3055
|
+
};
|
|
3056
|
+
} catch {
|
|
3057
|
+
return void 0;
|
|
3058
|
+
}
|
|
3059
|
+
};
|
|
3060
|
+
writeMemoryDreamState = async (options) => {
|
|
3061
|
+
const paths = scorelMemoryPaths(options);
|
|
3062
|
+
await mkdir3(paths.projectDir, { recursive: true, mode: 448 });
|
|
3063
|
+
const state = { ...options.state, projectId: options.projectId };
|
|
3064
|
+
await writeFile3(paths.dreamStatePath, `${JSON.stringify(state, null, 2)}
|
|
3065
|
+
`, { encoding: "utf8", mode: 384 });
|
|
3066
|
+
return state;
|
|
3067
|
+
};
|
|
2788
3068
|
readSessionMemory = async (options) => {
|
|
2789
3069
|
const paths = scorelSessionMemoryPaths(options);
|
|
2790
3070
|
return trimForContext(await readOptional(paths.sessionMemoryPath), 12e3, "tail");
|
|
@@ -2830,7 +3110,7 @@ var init_memory = __esm({
|
|
|
2830
3110
|
try {
|
|
2831
3111
|
await writeFile3(path, content, { encoding: "utf8", flag: "wx", mode: 384 });
|
|
2832
3112
|
} catch (cause) {
|
|
2833
|
-
if (!
|
|
3113
|
+
if (!isNodeErrorCode3(cause, "EEXIST")) {
|
|
2834
3114
|
throw cause;
|
|
2835
3115
|
}
|
|
2836
3116
|
}
|
|
@@ -2839,7 +3119,7 @@ var init_memory = __esm({
|
|
|
2839
3119
|
try {
|
|
2840
3120
|
return await readFile7(path, "utf8");
|
|
2841
3121
|
} catch (cause) {
|
|
2842
|
-
if (
|
|
3122
|
+
if (isNodeErrorCode3(cause, "ENOENT")) {
|
|
2843
3123
|
return "";
|
|
2844
3124
|
}
|
|
2845
3125
|
throw cause;
|
|
@@ -2860,7 +3140,7 @@ var init_memory = __esm({
|
|
|
2860
3140
|
normalizeMarkdownFile = (value) => `${value.trimEnd()}
|
|
2861
3141
|
`;
|
|
2862
3142
|
parseAppendDailyInput = (value) => {
|
|
2863
|
-
if (!
|
|
3143
|
+
if (!isRecord6(value)) {
|
|
2864
3144
|
throw new Error("AppendDaily args must be an object");
|
|
2865
3145
|
}
|
|
2866
3146
|
const summary = requireString3(value.summary, "summary");
|
|
@@ -2869,9 +3149,45 @@ var init_memory = __esm({
|
|
|
2869
3149
|
completed: optionalStringArray(value.completed, "completed"),
|
|
2870
3150
|
decisions: optionalStringArray(value.decisions, "decisions"),
|
|
2871
3151
|
followUps: optionalStringArray(value.followUps, "followUps"),
|
|
2872
|
-
memoryCandidates: optionalStringArray(value.memoryCandidates, "memoryCandidates")
|
|
3152
|
+
memoryCandidates: optionalStringArray(value.memoryCandidates, "memoryCandidates"),
|
|
3153
|
+
evidence: optionalStringArray(value.evidence, "evidence")
|
|
2873
3154
|
};
|
|
2874
3155
|
};
|
|
3156
|
+
validateAppendDailyInput = (input) => {
|
|
3157
|
+
const summary = compactLine(input.summary, 500);
|
|
3158
|
+
if (isLowSignalSummary(summary)) {
|
|
3159
|
+
throw new Error("AppendDaily.summary is too generic; include concrete durable progress or a decision");
|
|
3160
|
+
}
|
|
3161
|
+
const details = [
|
|
3162
|
+
...input.completed ?? [],
|
|
3163
|
+
...input.decisions ?? [],
|
|
3164
|
+
...input.followUps ?? [],
|
|
3165
|
+
...input.memoryCandidates ?? [],
|
|
3166
|
+
...input.evidence ?? []
|
|
3167
|
+
].map((value) => compactLine(value, 240)).filter(Boolean);
|
|
3168
|
+
if (details.length === 0) {
|
|
3169
|
+
throw new Error("AppendDaily requires at least one completed item, decision, follow-up, memory candidate, or evidence item");
|
|
3170
|
+
}
|
|
3171
|
+
};
|
|
3172
|
+
isLowSignalSummary = (value) => {
|
|
3173
|
+
const normalized = value.toLowerCase().replace(/\s+/g, "");
|
|
3174
|
+
return [
|
|
3175
|
+
"done",
|
|
3176
|
+
"completed",
|
|
3177
|
+
"finished",
|
|
3178
|
+
"updated",
|
|
3179
|
+
"\u7EE7\u7EED\u63A8\u8FDB",
|
|
3180
|
+
"\u5B8C\u6210\u4EFB\u52A1",
|
|
3181
|
+
"\u5DF2\u5904\u7406",
|
|
3182
|
+
"\u5904\u7406\u5B8C\u6210",
|
|
3183
|
+
"\u505A\u4E86\u4E00\u4E9B\u4FEE\u6539"
|
|
3184
|
+
].includes(normalized);
|
|
3185
|
+
};
|
|
3186
|
+
containsNormalizedDailyEntry = (daily, text) => {
|
|
3187
|
+
const needle = normalizeDailyText(text);
|
|
3188
|
+
return daily.split("\n").map((line) => line.replace(/^-\s+\d\d:\d\d\s+/, "")).some((line) => normalizeDailyText(line) === needle);
|
|
3189
|
+
};
|
|
3190
|
+
normalizeDailyText = (value) => value.replace(/\s+/g, " ").trim().toLowerCase();
|
|
2875
3191
|
requireString3 = (value, name) => {
|
|
2876
3192
|
if (typeof value !== "string" || !value.trim()) {
|
|
2877
3193
|
throw new Error(`AppendDaily.${name} must be a non-empty string`);
|
|
@@ -2887,14 +3203,22 @@ var init_memory = __esm({
|
|
|
2887
3203
|
}
|
|
2888
3204
|
return value.map((item) => item.trim()).filter(Boolean);
|
|
2889
3205
|
};
|
|
2890
|
-
|
|
3206
|
+
optionalNumber2 = (value) => typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
3207
|
+
optionalString3 = (value) => typeof value === "string" && value.trim() ? value : void 0;
|
|
3208
|
+
parseLastFailure = (value) => {
|
|
3209
|
+
if (!isRecord6(value)) return void 0;
|
|
3210
|
+
const at = optionalNumber2(value.at);
|
|
3211
|
+
const message = optionalString3(value.message);
|
|
3212
|
+
return at !== void 0 && message ? { at, message } : void 0;
|
|
3213
|
+
};
|
|
3214
|
+
isRecord6 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2891
3215
|
safeProjectId = (projectId) => {
|
|
2892
3216
|
if (!/^[A-Za-z0-9_-]+$/.test(projectId)) {
|
|
2893
3217
|
throw new Error("projectId must contain only letters, numbers, underscores, or hyphens");
|
|
2894
3218
|
}
|
|
2895
3219
|
return projectId;
|
|
2896
3220
|
};
|
|
2897
|
-
|
|
3221
|
+
isNodeErrorCode3 = (cause, code) => cause instanceof Error && "code" in cause && cause.code === code;
|
|
2898
3222
|
}
|
|
2899
3223
|
});
|
|
2900
3224
|
|
|
@@ -2921,6 +3245,8 @@ var init_pi_ai = __esm({
|
|
|
2921
3245
|
for await (const event of stream) {
|
|
2922
3246
|
if (event.type === "text_delta") {
|
|
2923
3247
|
yield { type: "text_delta", delta: event.delta };
|
|
3248
|
+
} else if (event.type === "thinking_delta") {
|
|
3249
|
+
yield { type: "thinking_delta", delta: event.delta };
|
|
2924
3250
|
}
|
|
2925
3251
|
}
|
|
2926
3252
|
return fromPiAssistant(await stream.result());
|
|
@@ -3111,7 +3437,8 @@ var init_pi_ai = __esm({
|
|
|
3111
3437
|
completed: Type.Optional(Type.Array(Type.String())),
|
|
3112
3438
|
decisions: Type.Optional(Type.Array(Type.String())),
|
|
3113
3439
|
followUps: Type.Optional(Type.Array(Type.String())),
|
|
3114
|
-
memoryCandidates: Type.Optional(Type.Array(Type.String()))
|
|
3440
|
+
memoryCandidates: Type.Optional(Type.Array(Type.String())),
|
|
3441
|
+
evidence: Type.Optional(Type.Array(Type.String()))
|
|
3115
3442
|
});
|
|
3116
3443
|
case "Skill":
|
|
3117
3444
|
return Type.Object({
|
|
@@ -3180,7 +3507,7 @@ var init_pi_ai = __esm({
|
|
|
3180
3507
|
});
|
|
3181
3508
|
|
|
3182
3509
|
// packages/core/src/runtime/index.ts
|
|
3183
|
-
var ScorelRuntime, normalizeAssistantMessage, isAssistantMessage, partialAssistantMessage;
|
|
3510
|
+
var ScorelRuntime, toolResultForContext, normalizeAssistantMessage, isAssistantMessage, partialAssistantMessage;
|
|
3184
3511
|
var init_runtime = __esm({
|
|
3185
3512
|
"packages/core/src/runtime/index.ts"() {
|
|
3186
3513
|
"use strict";
|
|
@@ -3250,6 +3577,7 @@ var init_runtime = __esm({
|
|
|
3250
3577
|
}
|
|
3251
3578
|
async *#runProviderTurn(context, systemPrompt, options, signal) {
|
|
3252
3579
|
let text = "";
|
|
3580
|
+
let thinking = "";
|
|
3253
3581
|
yield { type: "message_start", role: "assistant" };
|
|
3254
3582
|
try {
|
|
3255
3583
|
const stream = this.#provider.streamTurn({
|
|
@@ -3265,7 +3593,7 @@ var init_runtime = __esm({
|
|
|
3265
3593
|
}
|
|
3266
3594
|
const next = await stream.next();
|
|
3267
3595
|
if (next.done) {
|
|
3268
|
-
const message = normalizeAssistantMessage(next.value, text, signal.aborted ? "cancelled" : "end_turn");
|
|
3596
|
+
const message = normalizeAssistantMessage(next.value, { thinking, text }, signal.aborted ? "cancelled" : "end_turn");
|
|
3269
3597
|
if (message) {
|
|
3270
3598
|
yield { type: "message_end", message };
|
|
3271
3599
|
}
|
|
@@ -3274,16 +3602,19 @@ var init_runtime = __esm({
|
|
|
3274
3602
|
if (next.value.type === "text_delta") {
|
|
3275
3603
|
text += next.value.delta;
|
|
3276
3604
|
yield next.value;
|
|
3605
|
+
} else if (next.value.type === "thinking_delta") {
|
|
3606
|
+
thinking += next.value.delta;
|
|
3607
|
+
yield next.value;
|
|
3277
3608
|
}
|
|
3278
3609
|
}
|
|
3279
|
-
const cancelledMessage = partialAssistantMessage(text, "cancelled");
|
|
3610
|
+
const cancelledMessage = partialAssistantMessage({ thinking, text }, "cancelled");
|
|
3280
3611
|
if (cancelledMessage) {
|
|
3281
3612
|
yield { type: "message_end", message: cancelledMessage };
|
|
3282
3613
|
}
|
|
3283
3614
|
return { stopReason: "cancelled" };
|
|
3284
3615
|
} catch (cause) {
|
|
3285
3616
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
3286
|
-
const partial = partialAssistantMessage(text, "error");
|
|
3617
|
+
const partial = partialAssistantMessage({ thinking, text }, "error");
|
|
3287
3618
|
if (partial) {
|
|
3288
3619
|
yield { type: "message_end", message: partial };
|
|
3289
3620
|
}
|
|
@@ -3325,7 +3656,7 @@ var init_runtime = __esm({
|
|
|
3325
3656
|
type: "tool_result",
|
|
3326
3657
|
toolCallId: toolCall.toolCallId,
|
|
3327
3658
|
toolName: toolCall.toolName,
|
|
3328
|
-
result,
|
|
3659
|
+
result: toolResultForContext(result),
|
|
3329
3660
|
isError
|
|
3330
3661
|
};
|
|
3331
3662
|
return {
|
|
@@ -3334,23 +3665,29 @@ var init_runtime = __esm({
|
|
|
3334
3665
|
};
|
|
3335
3666
|
}
|
|
3336
3667
|
};
|
|
3337
|
-
|
|
3668
|
+
toolResultForContext = (result) => ({
|
|
3669
|
+
content: result.content
|
|
3670
|
+
});
|
|
3671
|
+
normalizeAssistantMessage = (value, streamed, fallbackStopReason) => {
|
|
3338
3672
|
if (value) {
|
|
3339
3673
|
if (!isAssistantMessage(value)) {
|
|
3340
3674
|
throw new Error(`Provider returned ${value.role} message instead of assistant`);
|
|
3341
3675
|
}
|
|
3342
3676
|
return value;
|
|
3343
3677
|
}
|
|
3344
|
-
return partialAssistantMessage(
|
|
3678
|
+
return partialAssistantMessage(streamed, fallbackStopReason);
|
|
3345
3679
|
};
|
|
3346
3680
|
isAssistantMessage = (message) => message.role === "assistant";
|
|
3347
|
-
partialAssistantMessage = (
|
|
3348
|
-
if (text.length === 0) {
|
|
3681
|
+
partialAssistantMessage = (streamed, stopReason) => {
|
|
3682
|
+
if (streamed.thinking.length === 0 && streamed.text.length === 0) {
|
|
3349
3683
|
return void 0;
|
|
3350
3684
|
}
|
|
3351
3685
|
return {
|
|
3352
3686
|
role: "assistant",
|
|
3353
|
-
content: [
|
|
3687
|
+
content: [
|
|
3688
|
+
...streamed.thinking ? [{ type: "thinking", text: streamed.thinking }] : [],
|
|
3689
|
+
...streamed.text ? [{ type: "text", text: streamed.text }] : []
|
|
3690
|
+
],
|
|
3354
3691
|
stopReason,
|
|
3355
3692
|
meta: stopReason === "end_turn" ? void 0 : { partial: true }
|
|
3356
3693
|
};
|
|
@@ -3362,7 +3699,7 @@ var init_runtime = __esm({
|
|
|
3362
3699
|
import { appendFile as appendFile2, mkdir as mkdir4, readFile as readFile8, writeFile as writeFile4 } from "node:fs/promises";
|
|
3363
3700
|
import { dirname as dirname6, join as join7 } from "node:path";
|
|
3364
3701
|
function assertTreeEvent(value) {
|
|
3365
|
-
if (!
|
|
3702
|
+
if (!isRecord7(value)) {
|
|
3366
3703
|
throw new SessionStoreError("invalid_event", "Event must be an object");
|
|
3367
3704
|
}
|
|
3368
3705
|
if (value.type === "session_header") {
|
|
@@ -3374,7 +3711,7 @@ function assertTreeEvent(value) {
|
|
|
3374
3711
|
if (typeof value.id !== "string" || value.parentId !== null && typeof value.parentId !== "string" || typeof value.seq !== "number" || typeof value.clientId !== "string" || typeof value.ts !== "number") {
|
|
3375
3712
|
throw new SessionStoreError("invalid_event", "Event is missing required base fields");
|
|
3376
3713
|
}
|
|
3377
|
-
if ((value.type === "user_message" || value.type === "assistant_message" || value.type === "tool_result") && !
|
|
3714
|
+
if ((value.type === "user_message" || value.type === "assistant_message" || value.type === "tool_result") && !isRecord7(value.message)) {
|
|
3378
3715
|
throw new SessionStoreError("invalid_event", "Message event is missing message payload");
|
|
3379
3716
|
}
|
|
3380
3717
|
if (value.type === "session_title_updated" && !isSessionTitleUpdated(value)) {
|
|
@@ -3399,7 +3736,7 @@ function assertTreeEvent(value) {
|
|
|
3399
3736
|
throw new SessionStoreError("invalid_event", "skill_index_delta is missing delta payload");
|
|
3400
3737
|
}
|
|
3401
3738
|
}
|
|
3402
|
-
var SessionStoreError, SessionTree, JsonlSession, sessionFilePath, sessionLogFilePath, createSession, loadSession, buildContext, retainedMessagesBeforeCompact, isRetainedContextStart, parseJsonLine, parseHeader, parseSessionEvent, validateSessionMatch, isConversationEvent, isInstructionSnapshot, isHarnessItem, isCompactEvent, isQueueUpdate, isSessionTitleUpdated, isSkillIndexSnapshot, isSkillIndexDelta, isSkillIndexEntry, appendHarnessItemToContext, appendReminderToToolResult, isToolResultWithContent, renderSystemReminder, compactSummaryMessage, cloneMessage,
|
|
3739
|
+
var SessionStoreError, SessionTree, JsonlSession, sessionFilePath, sessionLogFilePath, createSession, loadSession, buildContext, retainedMessagesBeforeCompact, isRetainedContextStart, parseJsonLine, parseHeader, parseSessionEvent, validateSessionMatch, isConversationEvent, isInstructionSnapshot, isHarnessItem, isCompactEvent, isQueueUpdate, isSessionTitleUpdated, isSkillIndexSnapshot, isSkillIndexDelta, isSkillIndexEntry, appendHarnessItemToContext, appendReminderToToolResult, isToolResultWithContent, renderSystemReminder, compactSummaryMessage, cloneMessage, isRecord7;
|
|
3403
3740
|
var init_session = __esm({
|
|
3404
3741
|
"packages/core/src/session/index.ts"() {
|
|
3405
3742
|
"use strict";
|
|
@@ -3667,13 +4004,13 @@ var init_session = __esm({
|
|
|
3667
4004
|
}
|
|
3668
4005
|
};
|
|
3669
4006
|
parseHeader = (value) => {
|
|
3670
|
-
if (!
|
|
4007
|
+
if (!isRecord7(value)) {
|
|
3671
4008
|
throw new SessionStoreError("invalid_header", "Session header must be an object");
|
|
3672
4009
|
}
|
|
3673
4010
|
if (value.version !== 1 || typeof value.sessionId !== "string" || typeof value.deviceId !== "string") {
|
|
3674
4011
|
throw new SessionStoreError("invalid_header", "Session header is missing required identity fields");
|
|
3675
4012
|
}
|
|
3676
|
-
if (typeof value.createdAt !== "number" || !
|
|
4013
|
+
if (typeof value.createdAt !== "number" || !isRecord7(value.meta)) {
|
|
3677
4014
|
throw new SessionStoreError("invalid_header", "Session header is missing createdAt or meta");
|
|
3678
4015
|
}
|
|
3679
4016
|
if (typeof value.meta.projectId !== "string" || value.meta.projectId.length === 0) {
|
|
@@ -3687,7 +4024,7 @@ var init_session = __esm({
|
|
|
3687
4024
|
return value;
|
|
3688
4025
|
};
|
|
3689
4026
|
validateSessionMatch = (header, value) => {
|
|
3690
|
-
if (!
|
|
4027
|
+
if (!isRecord7(value) || typeof value.sessionId !== "string") {
|
|
3691
4028
|
throw new SessionStoreError("invalid_header", "Event must be an object with a sessionId");
|
|
3692
4029
|
}
|
|
3693
4030
|
if (value.sessionId !== header.sessionId) {
|
|
@@ -3696,24 +4033,24 @@ var init_session = __esm({
|
|
|
3696
4033
|
};
|
|
3697
4034
|
isConversationEvent = (event) => event.type === "user_message" || event.type === "assistant_message" || event.type === "tool_result" || event.type === "harness_item" || event.type === "compact";
|
|
3698
4035
|
isInstructionSnapshot = (value) => {
|
|
3699
|
-
if (!
|
|
4036
|
+
if (!isRecord7(value) || value.version !== 1 || typeof value.cwd !== "string" || !Array.isArray(value.sections)) {
|
|
3700
4037
|
return false;
|
|
3701
4038
|
}
|
|
3702
4039
|
return value.sections.every(
|
|
3703
|
-
(section2) =>
|
|
4040
|
+
(section2) => isRecord7(section2) && typeof section2.kind === "string" && typeof section2.frozenAt === "number" && typeof section2.renderedBlock === "string"
|
|
3704
4041
|
);
|
|
3705
4042
|
};
|
|
3706
|
-
isHarnessItem = (value) =>
|
|
4043
|
+
isHarnessItem = (value) => isRecord7(value) && typeof value.kind === "string" && typeof value.origin === "string" && typeof value.content === "string" && (value.visibility === "display" || value.visibility === "hidden" || value.visibility === "compact");
|
|
3707
4044
|
isCompactEvent = (value) => typeof value.summary === "string" && typeof value.compactedThrough === "string" && typeof value.tokensBefore === "number" && typeof value.tokensAfter === "number" && typeof value.retainedEventCount === "number";
|
|
3708
4045
|
isQueueUpdate = (value) => (value.queue === "follow_up" || value.queue === "steer") && value.operation === "rewrite" && Array.isArray(value.items) && (value.anchorEventId === null || typeof value.anchorEventId === "string") && value.items.every(
|
|
3709
|
-
(item) =>
|
|
4046
|
+
(item) => isRecord7(item) && typeof item.id === "string" && Array.isArray(item.content) && typeof item.createdAt === "number" && typeof item.updatedAt === "number" && typeof item.clientId === "string"
|
|
3710
4047
|
);
|
|
3711
|
-
isSessionTitleUpdated = (value) => typeof value.title === "string" && value.title.length > 0 && (value.source === "model" || value.source === "user") && (value.derivedFrom === void 0 ||
|
|
4048
|
+
isSessionTitleUpdated = (value) => typeof value.title === "string" && value.title.length > 0 && (value.source === "model" || value.source === "user") && (value.derivedFrom === void 0 || isRecord7(value.derivedFrom) && typeof value.derivedFrom.eventId === "string" && typeof value.derivedFrom.seq === "number");
|
|
3712
4049
|
isSkillIndexSnapshot = (value) => (value.anchorEventId === null || typeof value.anchorEventId === "string") && Array.isArray(value.entries) && value.entries.every(isSkillIndexEntry);
|
|
3713
4050
|
isSkillIndexDelta = (value) => (value.anchorEventId === null || typeof value.anchorEventId === "string") && Array.isArray(value.added) && Array.isArray(value.changed) && Array.isArray(value.removed) && value.added.every(isSkillIndexEntry) && value.changed.every(isSkillIndexEntry) && value.removed.every(
|
|
3714
|
-
(item) =>
|
|
4051
|
+
(item) => isRecord7(item) && typeof item.name === "string" && typeof item.previousPath === "string"
|
|
3715
4052
|
);
|
|
3716
|
-
isSkillIndexEntry = (value) =>
|
|
4053
|
+
isSkillIndexEntry = (value) => isRecord7(value) && typeof value.name === "string" && typeof value.path === "string" && (value.scope === "user" || value.scope === "project" || value.scope === "extension") && typeof value.description === "string" && typeof value.mtimeMs === "number" && typeof value.size === "number" && typeof value.contentHash === "string" && typeof value.priority === "number";
|
|
3717
4054
|
appendHarnessItemToContext = (messages, event) => {
|
|
3718
4055
|
const reminder = renderSystemReminder(event.item.content);
|
|
3719
4056
|
const last = messages.at(-1);
|
|
@@ -3750,7 +4087,7 @@ ${reminder}` }]
|
|
|
3750
4087
|
}
|
|
3751
4088
|
return false;
|
|
3752
4089
|
};
|
|
3753
|
-
isToolResultWithContent = (value) =>
|
|
4090
|
+
isToolResultWithContent = (value) => isRecord7(value) && Array.isArray(value.content);
|
|
3754
4091
|
renderSystemReminder = (content) => `<system-reminder>
|
|
3755
4092
|
${content}
|
|
3756
4093
|
</system-reminder>`;
|
|
@@ -3774,21 +4111,20 @@ ${content}
|
|
|
3774
4111
|
cloneMessage = (message) => ({
|
|
3775
4112
|
...message,
|
|
3776
4113
|
content: message.content.map((block) => {
|
|
3777
|
-
if (block.type !== "tool_result" || !
|
|
4114
|
+
if (block.type !== "tool_result" || !isRecord7(block.result)) {
|
|
3778
4115
|
return { ...block };
|
|
3779
4116
|
}
|
|
3780
|
-
const content = Array.isArray(block.result.content) ? { content: block.result.content.map((item) =>
|
|
4117
|
+
const content = Array.isArray(block.result.content) ? { content: block.result.content.map((item) => isRecord7(item) ? { ...item } : item) } : {};
|
|
3781
4118
|
return {
|
|
3782
4119
|
...block,
|
|
3783
4120
|
result: {
|
|
3784
|
-
|
|
3785
|
-
...content
|
|
4121
|
+
content: content.content ?? []
|
|
3786
4122
|
}
|
|
3787
4123
|
};
|
|
3788
4124
|
}),
|
|
3789
4125
|
...message.meta ? { meta: { ...message.meta } } : {}
|
|
3790
4126
|
});
|
|
3791
|
-
|
|
4127
|
+
isRecord7 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3792
4128
|
}
|
|
3793
4129
|
});
|
|
3794
4130
|
|
|
@@ -3798,7 +4134,7 @@ import { existsSync as existsSync2 } from "node:fs";
|
|
|
3798
4134
|
import { readdir as readdir5, readFile as readFile9, stat as stat4 } from "node:fs/promises";
|
|
3799
4135
|
import { homedir as homedir4 } from "node:os";
|
|
3800
4136
|
import { dirname as dirname7, join as join8, resolve as resolve4 } from "node:path";
|
|
3801
|
-
var scanSkillIndex, diffSkillIndex, hasSkillIndexDelta, renderSkillListing, renderSkillDelta, createSkillTool, projectSkillRoots, readSkillEntry, parseSkillMetadata, firstParagraph, parseSkillArgs, findGitRoot2,
|
|
4137
|
+
var scanSkillIndex, diffSkillIndex, hasSkillIndexDelta, renderSkillListing, renderSkillDelta, createSkillTool, projectSkillRoots, readSkillEntry, parseSkillMetadata, firstParagraph, parseSkillArgs, findGitRoot2, isNodeErrorCode4;
|
|
3802
4138
|
var init_skills = __esm({
|
|
3803
4139
|
"packages/core/src/skills/index.ts"() {
|
|
3804
4140
|
"use strict";
|
|
@@ -3821,7 +4157,7 @@ var init_skills = __esm({
|
|
|
3821
4157
|
try {
|
|
3822
4158
|
children = await readdir5(root.path);
|
|
3823
4159
|
} catch (cause) {
|
|
3824
|
-
if (
|
|
4160
|
+
if (isNodeErrorCode4(cause, "ENOENT") || isNodeErrorCode4(cause, "ENOTDIR")) {
|
|
3825
4161
|
continue;
|
|
3826
4162
|
}
|
|
3827
4163
|
throw cause;
|
|
@@ -3934,7 +4270,7 @@ var init_skills = __esm({
|
|
|
3934
4270
|
try {
|
|
3935
4271
|
[fileStat, content] = await Promise.all([stat4(options.skillPath), readFile9(options.skillPath, "utf8")]);
|
|
3936
4272
|
} catch (cause) {
|
|
3937
|
-
if (
|
|
4273
|
+
if (isNodeErrorCode4(cause, "ENOENT") || isNodeErrorCode4(cause, "ENOTDIR")) {
|
|
3938
4274
|
return void 0;
|
|
3939
4275
|
}
|
|
3940
4276
|
throw cause;
|
|
@@ -4014,7 +4350,7 @@ var init_skills = __esm({
|
|
|
4014
4350
|
current = next;
|
|
4015
4351
|
}
|
|
4016
4352
|
};
|
|
4017
|
-
|
|
4353
|
+
isNodeErrorCode4 = (cause, code) => cause instanceof Error && "code" in cause && cause.code === code;
|
|
4018
4354
|
}
|
|
4019
4355
|
});
|
|
4020
4356
|
|
|
@@ -4360,12 +4696,15 @@ var init_host_client = __esm({
|
|
|
4360
4696
|
});
|
|
4361
4697
|
|
|
4362
4698
|
// packages/daemon/src/index.ts
|
|
4699
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
4363
4700
|
import { existsSync as existsSync3 } from "node:fs";
|
|
4364
|
-
import { appendFile as appendFile3, mkdir as mkdir6, readFile as readFile11, readdir as readdir6, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
4365
|
-
import {
|
|
4701
|
+
import { appendFile as appendFile3, mkdir as mkdir6, readFile as readFile11, readdir as readdir6, rename as rename3, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
4702
|
+
import { userInfo as userInfo2 } from "node:os";
|
|
4703
|
+
import { basename as basename3, dirname as dirname8, join as join10, resolve as resolve5 } from "node:path";
|
|
4366
4704
|
import { pathToFileURL } from "node:url";
|
|
4705
|
+
import { promisify as promisify2 } from "node:util";
|
|
4367
4706
|
import { WebSocketServer } from "ws";
|
|
4368
|
-
var daemonPackageName, SESSION_MEMORY_COMPACT_WAIT_MS, AUTO_COMPACT_RETAINED_EVENTS, localDaemonStateFile, createLocalDaemonState, readLocalDaemonState, removeLocalDaemonState, markDaemonStopped, daemonStateLiveness, defaultIsPidAlive, startRemoteDaemonWebSocketServer, startScorelHostWebSocketServer, closeWebSocketServer, createRealRuntime, ScorelHost, isMissingConfigError, createEmbeddedTransport,
|
|
4707
|
+
var daemonPackageName, SESSION_MEMORY_COMPACT_WAIT_MS, AUTO_COMPACT_RETAINED_EVENTS, execFileAsync2, localDaemonStateFile, createLocalDaemonState, readLocalDaemonState, removeLocalDaemonState, markDaemonStopped, daemonStateLiveness, defaultIsPidAlive, startRemoteDaemonWebSocketServer, startScorelHostWebSocketServer, closeWebSocketServer, createRealRuntime, ScorelHost, isMissingConfigError, createEmbeddedTransport, isNodeErrorCode5, wireErrorCode, hasContinuousCoverage, countContentBlocks, normalizeContent, inputText, assistantText, messageText, estimateScorelMessagesTokens, estimateTextTokens, compactLine2, parseSessionMemoryJson, stringArray, disabledMemorySettings, detectRtk, ensureRtkAvailable, emptyRuntimeStats, readRuntimeStats, writeRuntimeStats, parseRuntimeStats, parseRuntimeStatsBuckets, addRtkSavings, addRuntimeStatsBucket, rtkSavingsFromToolResult, nonNegativeInteger2, resolveDefaultShell2, shellCommandArgs2, userShell2, runtimeChannelContextFromWire, parseQueuedChannelContext, imBindingKey, defaultBuiltinExtensionsDir, runtimeModuleDir, findBuiltinExtensionsDir, isSteerMessage, stripImCommandPrefix, isRecord8, parseMemoryUpdate, normalizeMarkdownFile2, sanitizeSessionTitle, shortStack, formatDiagnosticLine, formatDiagnosticValue;
|
|
4369
4708
|
var init_src4 = __esm({
|
|
4370
4709
|
"packages/daemon/src/index.ts"() {
|
|
4371
4710
|
"use strict";
|
|
@@ -4380,6 +4719,7 @@ var init_src4 = __esm({
|
|
|
4380
4719
|
daemonPackageName = "@scorel/daemon";
|
|
4381
4720
|
SESSION_MEMORY_COMPACT_WAIT_MS = 5e3;
|
|
4382
4721
|
AUTO_COMPACT_RETAINED_EVENTS = 8;
|
|
4722
|
+
execFileAsync2 = promisify2(execFile2);
|
|
4383
4723
|
localDaemonStateFile = (stateDir) => join10(stateDir, "daemon.json");
|
|
4384
4724
|
createLocalDaemonState = async (options) => {
|
|
4385
4725
|
const state = {
|
|
@@ -4591,9 +4931,10 @@ var init_src4 = __esm({
|
|
|
4591
4931
|
}
|
|
4592
4932
|
server.close((error) => error ? reject(error) : resolve7());
|
|
4593
4933
|
});
|
|
4594
|
-
createRealRuntime = (options) => {
|
|
4934
|
+
createRealRuntime = async (options) => {
|
|
4595
4935
|
const selection = resolveModelSelection(options.config, options.modelSelection);
|
|
4596
4936
|
const model = resolvePiAiModel(selection.config);
|
|
4937
|
+
const rtkExecutable = options.rtkExecutable ?? (options.config.runtime.tokenSavingRtk ? (await detectRtk()).executable : void 0);
|
|
4597
4938
|
const runtime = new ScorelRuntime({
|
|
4598
4939
|
provider: createPiAiProvider({
|
|
4599
4940
|
model,
|
|
@@ -4601,7 +4942,16 @@ var init_src4 = __esm({
|
|
|
4601
4942
|
})
|
|
4602
4943
|
});
|
|
4603
4944
|
if (options.includeTools !== false) {
|
|
4604
|
-
for (const tool of createCodingTools({
|
|
4945
|
+
for (const tool of createCodingTools({
|
|
4946
|
+
cwd: options.cwd,
|
|
4947
|
+
contextWindow: model.contextWindow,
|
|
4948
|
+
tokenSaving: {
|
|
4949
|
+
rtk: {
|
|
4950
|
+
enabled: options.config.runtime.tokenSavingRtk,
|
|
4951
|
+
executable: rtkExecutable
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
})) {
|
|
4605
4955
|
runtime.registerTool(tool);
|
|
4606
4956
|
}
|
|
4607
4957
|
}
|
|
@@ -4619,6 +4969,9 @@ var init_src4 = __esm({
|
|
|
4619
4969
|
#loadConfigProfile;
|
|
4620
4970
|
#createRuntime;
|
|
4621
4971
|
#memoryHomeDir;
|
|
4972
|
+
#onSessionListChanged;
|
|
4973
|
+
#idleShutdownMs;
|
|
4974
|
+
#onIdleShutdown;
|
|
4622
4975
|
#now;
|
|
4623
4976
|
#createId;
|
|
4624
4977
|
#sessions = /* @__PURE__ */ new Map();
|
|
@@ -4630,6 +4983,8 @@ var init_src4 = __esm({
|
|
|
4630
4983
|
#imExtensions = /* @__PURE__ */ new Map();
|
|
4631
4984
|
#imBindings = /* @__PURE__ */ new Map();
|
|
4632
4985
|
#registry;
|
|
4986
|
+
#runtimeStatsQueue = Promise.resolve();
|
|
4987
|
+
#idleShutdownTimer;
|
|
4633
4988
|
#started = false;
|
|
4634
4989
|
constructor(options) {
|
|
4635
4990
|
this.#sessionsDir = options.sessionsDir;
|
|
@@ -4643,6 +4998,9 @@ var init_src4 = __esm({
|
|
|
4643
4998
|
this.#loadConfigProfile = options.loadConfigProfile;
|
|
4644
4999
|
this.#createRuntime = options.createRuntime;
|
|
4645
5000
|
this.#memoryHomeDir = options.memoryHomeDir;
|
|
5001
|
+
this.#onSessionListChanged = options.onSessionListChanged;
|
|
5002
|
+
this.#idleShutdownMs = options.idleShutdownMs;
|
|
5003
|
+
this.#onIdleShutdown = options.onIdleShutdown;
|
|
4646
5004
|
this.#now = options.now ?? Date.now;
|
|
4647
5005
|
this.#createId = options.createId ?? (() => crypto.randomUUID());
|
|
4648
5006
|
this.#registry = new ProjectRegistry({
|
|
@@ -4657,8 +5015,10 @@ var init_src4 = __esm({
|
|
|
4657
5015
|
await mkdir6(this.#scorelHomeDir, { recursive: true });
|
|
4658
5016
|
await this.#loadImBindings();
|
|
4659
5017
|
await this.#startEnabledImExtensions();
|
|
5018
|
+
this.#scheduleIdleShutdownCheck();
|
|
4660
5019
|
}
|
|
4661
5020
|
async shutdown() {
|
|
5021
|
+
this.#clearIdleShutdownTimer();
|
|
4662
5022
|
for (const schedule of this.#memoryDreams.values()) {
|
|
4663
5023
|
if (schedule.timer) {
|
|
4664
5024
|
clearTimeout(schedule.timer);
|
|
@@ -4673,9 +5033,11 @@ var init_src4 = __esm({
|
|
|
4673
5033
|
this.#assertStarted();
|
|
4674
5034
|
await this.#stopImExtensions();
|
|
4675
5035
|
await this.#startEnabledImExtensions();
|
|
5036
|
+
this.#scheduleIdleShutdownCheck();
|
|
4676
5037
|
}
|
|
4677
5038
|
connect(connection, sessionId) {
|
|
4678
5039
|
this.#assertStarted();
|
|
5040
|
+
this.#clearIdleShutdownTimer();
|
|
4679
5041
|
connection.sessionId = sessionId;
|
|
4680
5042
|
this.#connections.add(connection);
|
|
4681
5043
|
if (sessionId) {
|
|
@@ -4700,6 +5062,7 @@ var init_src4 = __esm({
|
|
|
4700
5062
|
});
|
|
4701
5063
|
}
|
|
4702
5064
|
this.#connections.delete(connection);
|
|
5065
|
+
this.#scheduleIdleShutdownCheck();
|
|
4703
5066
|
}
|
|
4704
5067
|
releaseSessionEventBuffer(sessionId) {
|
|
4705
5068
|
this.#events.delete(sessionId);
|
|
@@ -4720,6 +5083,8 @@ var init_src4 = __esm({
|
|
|
4720
5083
|
return;
|
|
4721
5084
|
}
|
|
4722
5085
|
throw cause;
|
|
5086
|
+
} finally {
|
|
5087
|
+
this.#scheduleIdleShutdownCheck();
|
|
4723
5088
|
}
|
|
4724
5089
|
}
|
|
4725
5090
|
async listDirectories(path) {
|
|
@@ -4819,18 +5184,34 @@ var init_src4 = __esm({
|
|
|
4819
5184
|
this.#respond(connection, message, await this.#handleUpsertModelProfile(message));
|
|
4820
5185
|
break;
|
|
4821
5186
|
}
|
|
5187
|
+
case "remove_model_provider": {
|
|
5188
|
+
this.#respond(connection, message, await this.#handleRemoveModelProvider(message));
|
|
5189
|
+
break;
|
|
5190
|
+
}
|
|
4822
5191
|
case "fetch_provider_models": {
|
|
4823
5192
|
this.#respond(connection, message, { models: await this.#fetchProviderModels(message.projectId, message.providerId) });
|
|
4824
5193
|
break;
|
|
4825
5194
|
}
|
|
4826
5195
|
case "get_memory_settings": {
|
|
4827
|
-
this.#respond(connection, message, { memory: await this.#
|
|
5196
|
+
this.#respond(connection, message, { memory: await this.#memorySettings(message.projectId) });
|
|
5197
|
+
break;
|
|
5198
|
+
}
|
|
5199
|
+
case "get_memory_status": {
|
|
5200
|
+
this.#respond(connection, message, { status: await this.#memoryStatusForProject(message.projectId) });
|
|
4828
5201
|
break;
|
|
4829
5202
|
}
|
|
4830
5203
|
case "upsert_memory_settings": {
|
|
4831
5204
|
this.#respond(connection, message, { memory: await this.#handleUpsertMemorySettings(message) });
|
|
4832
5205
|
break;
|
|
4833
5206
|
}
|
|
5207
|
+
case "get_runtime_settings": {
|
|
5208
|
+
this.#respond(connection, message, { runtime: await this.#runtimeSettings(message.projectId) });
|
|
5209
|
+
break;
|
|
5210
|
+
}
|
|
5211
|
+
case "upsert_runtime_settings": {
|
|
5212
|
+
this.#respond(connection, message, { runtime: await this.#handleUpsertRuntimeSettings(message) });
|
|
5213
|
+
break;
|
|
5214
|
+
}
|
|
4834
5215
|
case "get_extension_settings": {
|
|
4835
5216
|
this.#respond(connection, message, { extension: await this.#extensionSettings(message.extensionId) });
|
|
4836
5217
|
break;
|
|
@@ -4859,6 +5240,39 @@ var init_src4 = __esm({
|
|
|
4859
5240
|
break;
|
|
4860
5241
|
}
|
|
4861
5242
|
}
|
|
5243
|
+
#scheduleIdleShutdownCheck() {
|
|
5244
|
+
this.#clearIdleShutdownTimer();
|
|
5245
|
+
if (!this.#shouldIdleShutdown()) {
|
|
5246
|
+
return;
|
|
5247
|
+
}
|
|
5248
|
+
this.#idleShutdownTimer = setTimeout(() => {
|
|
5249
|
+
this.#idleShutdownTimer = void 0;
|
|
5250
|
+
if (this.#shouldIdleShutdown()) {
|
|
5251
|
+
this.#onIdleShutdown?.();
|
|
5252
|
+
}
|
|
5253
|
+
}, this.#idleShutdownMs);
|
|
5254
|
+
}
|
|
5255
|
+
#clearIdleShutdownTimer() {
|
|
5256
|
+
if (!this.#idleShutdownTimer) {
|
|
5257
|
+
return;
|
|
5258
|
+
}
|
|
5259
|
+
clearTimeout(this.#idleShutdownTimer);
|
|
5260
|
+
this.#idleShutdownTimer = void 0;
|
|
5261
|
+
}
|
|
5262
|
+
#shouldIdleShutdown() {
|
|
5263
|
+
return this.#started && this.#idleShutdownMs !== void 0 && this.#idleShutdownMs > 0 && this.#connections.size === 0 && this.#imExtensions.size === 0 && !this.#hasActiveWork();
|
|
5264
|
+
}
|
|
5265
|
+
#hasActiveWork() {
|
|
5266
|
+
for (const lane of this.#sessions.values()) {
|
|
5267
|
+
if (lane.runtime.running) {
|
|
5268
|
+
return true;
|
|
5269
|
+
}
|
|
5270
|
+
if (lane.session.tree.controlState.queues.follow_up.length > 0 || lane.session.tree.controlState.queues.steer.length > 0) {
|
|
5271
|
+
return true;
|
|
5272
|
+
}
|
|
5273
|
+
}
|
|
5274
|
+
return false;
|
|
5275
|
+
}
|
|
4862
5276
|
async #handleCreateSession(connection, request) {
|
|
4863
5277
|
const sessionId = request.sessionId ?? asSessionId(`ses_${this.#createId()}`);
|
|
4864
5278
|
const project = await this.#resolveProject(sessionId, request.meta.projectId);
|
|
@@ -4875,7 +5289,7 @@ var init_src4 = __esm({
|
|
|
4875
5289
|
try {
|
|
4876
5290
|
lane = await this.#createLane(sessionId, request.meta, project);
|
|
4877
5291
|
} catch (cause) {
|
|
4878
|
-
if (!request.sessionId || !
|
|
5292
|
+
if (!request.sessionId || !isNodeErrorCode5(cause, "EEXIST")) {
|
|
4879
5293
|
throw cause;
|
|
4880
5294
|
}
|
|
4881
5295
|
lane = await this.#getLane(sessionId);
|
|
@@ -4892,6 +5306,9 @@ var init_src4 = __esm({
|
|
|
4892
5306
|
workDir: lane.project.workDir,
|
|
4893
5307
|
model: request.meta.model
|
|
4894
5308
|
});
|
|
5309
|
+
if (created) {
|
|
5310
|
+
this.#onSessionListChanged?.({ projectId: lane.project.projectId, sessionId });
|
|
5311
|
+
}
|
|
4895
5312
|
this.#respond(connection, request, { sessionId });
|
|
4896
5313
|
}
|
|
4897
5314
|
async #handleLoadSession(connection, request) {
|
|
@@ -5332,10 +5749,21 @@ var init_src4 = __esm({
|
|
|
5332
5749
|
delta: rawEvent.delta
|
|
5333
5750
|
});
|
|
5334
5751
|
break;
|
|
5752
|
+
case "thinking_delta":
|
|
5753
|
+
this.#broadcastTransient(lane.session.header.sessionId, {
|
|
5754
|
+
type: "thinking_delta",
|
|
5755
|
+
sessionId: lane.session.header.sessionId,
|
|
5756
|
+
clientId,
|
|
5757
|
+
ts: this.#now(),
|
|
5758
|
+
eventId: state.assistantEventId,
|
|
5759
|
+
delta: rawEvent.delta
|
|
5760
|
+
});
|
|
5761
|
+
break;
|
|
5335
5762
|
case "message_end": {
|
|
5336
5763
|
await this.#appendDiagnostic(lane.session.header.sessionId, "assistant_result", {
|
|
5337
5764
|
clientId,
|
|
5338
5765
|
stopReason: rawEvent.message.stopReason,
|
|
5766
|
+
thinkingBlocks: countContentBlocks(rawEvent.message, "thinking"),
|
|
5339
5767
|
textBlocks: countContentBlocks(rawEvent.message, "text"),
|
|
5340
5768
|
toolCalls: countContentBlocks(rawEvent.message, "tool_call"),
|
|
5341
5769
|
inputTokens: rawEvent.message.usage?.inputTokens,
|
|
@@ -5380,6 +5808,18 @@ var init_src4 = __esm({
|
|
|
5380
5808
|
]
|
|
5381
5809
|
}
|
|
5382
5810
|
});
|
|
5811
|
+
const rtkSavings = rtkSavingsFromToolResult(rawEvent.result);
|
|
5812
|
+
if (rtkSavings) {
|
|
5813
|
+
await this.#recordRtkSavings({
|
|
5814
|
+
projectId: lane.project.projectId,
|
|
5815
|
+
sessionId: lane.session.header.sessionId,
|
|
5816
|
+
savings: rtkSavings
|
|
5817
|
+
}).catch(
|
|
5818
|
+
(cause) => this.#appendDiagnostic(lane.session.header.sessionId, "runtime_stats_update_failed", {
|
|
5819
|
+
message: cause instanceof Error ? cause.message : String(cause)
|
|
5820
|
+
})
|
|
5821
|
+
);
|
|
5822
|
+
}
|
|
5383
5823
|
state.parentId = toolResultId;
|
|
5384
5824
|
break;
|
|
5385
5825
|
}
|
|
@@ -5531,12 +5971,21 @@ var init_src4 = __esm({
|
|
|
5531
5971
|
homeDir: this.#memoryHomeDir,
|
|
5532
5972
|
now: this.#now,
|
|
5533
5973
|
onAppend: async (result) => {
|
|
5534
|
-
|
|
5535
|
-
clientId,
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5974
|
+
if (result.entry) {
|
|
5975
|
+
await this.#markMemoryDreamDirty(lane, clientId, result.path);
|
|
5976
|
+
}
|
|
5977
|
+
try {
|
|
5978
|
+
await this.#appendDiagnostic(lane.session.header.sessionId, "memory_daily_appended", {
|
|
5979
|
+
clientId,
|
|
5980
|
+
path: result.path,
|
|
5981
|
+
date: result.date,
|
|
5982
|
+
skippedReason: result.skippedReason
|
|
5983
|
+
});
|
|
5984
|
+
} catch {
|
|
5985
|
+
}
|
|
5986
|
+
if (result.entry) {
|
|
5987
|
+
await this.#scheduleMemoryDream(lane, clientId);
|
|
5988
|
+
}
|
|
5540
5989
|
}
|
|
5541
5990
|
})
|
|
5542
5991
|
);
|
|
@@ -5767,7 +6216,10 @@ var init_src4 = __esm({
|
|
|
5767
6216
|
...context.senderDisplayName ? [`sender_display_name: ${context.senderDisplayName}`] : [],
|
|
5768
6217
|
...context.mentionedBot !== void 0 ? [`mentioned_bot: ${context.mentionedBot}`] : [],
|
|
5769
6218
|
"",
|
|
5770
|
-
"Use SendChannelMessage to reply to the current conversation when needed."
|
|
6219
|
+
"Use SendChannelMessage to reply to the current conversation when needed.",
|
|
6220
|
+
"In IM, send a short acknowledgement before long work so the user does not think the bot is stuck.",
|
|
6221
|
+
"For longer tasks, send concise progress updates instead of waiting until every tool call has finished.",
|
|
6222
|
+
"Keep replies conversational and avoid exposing internal tool names unless they help the user."
|
|
5771
6223
|
];
|
|
5772
6224
|
return this.#appendPersistent(lane, {
|
|
5773
6225
|
type: "harness_item",
|
|
@@ -5808,6 +6260,22 @@ var init_src4 = __esm({
|
|
|
5808
6260
|
lastActivityAt: this.#now()
|
|
5809
6261
|
};
|
|
5810
6262
|
const delayMs = Math.max(0, memory.dreamIdleMinutes) * 60 * 1e3;
|
|
6263
|
+
const scheduledFor = this.#now() + delayMs;
|
|
6264
|
+
const currentState = await readMemoryDreamState({
|
|
6265
|
+
projectId: lane.project.projectId,
|
|
6266
|
+
homeDir: this.#memoryHomeDir,
|
|
6267
|
+
now: this.#now
|
|
6268
|
+
});
|
|
6269
|
+
await this.#writeMemoryDreamState(lane.project.projectId, {
|
|
6270
|
+
...currentState ?? {},
|
|
6271
|
+
projectId: String(lane.project.projectId),
|
|
6272
|
+
dirty: true,
|
|
6273
|
+
running: schedule.running,
|
|
6274
|
+
sessionId: String(lane.session.header.sessionId),
|
|
6275
|
+
clientId: String(clientId),
|
|
6276
|
+
lastDailyAppendAt: currentState?.lastDailyAppendAt ?? schedule.lastActivityAt,
|
|
6277
|
+
scheduledFor
|
|
6278
|
+
});
|
|
5811
6279
|
schedule.timer = setTimeout(() => {
|
|
5812
6280
|
void this.#runIdleMemoryDream(projectId).catch((cause) => {
|
|
5813
6281
|
const error = cause instanceof Error ? cause : new Error(String(cause));
|
|
@@ -5826,6 +6294,26 @@ var init_src4 = __esm({
|
|
|
5826
6294
|
idleMinutes: memory.dreamIdleMinutes
|
|
5827
6295
|
});
|
|
5828
6296
|
}
|
|
6297
|
+
async #markMemoryDreamDirty(lane, clientId, dailyPath) {
|
|
6298
|
+
const current = await readMemoryDreamState({
|
|
6299
|
+
projectId: lane.project.projectId,
|
|
6300
|
+
homeDir: this.#memoryHomeDir,
|
|
6301
|
+
now: this.#now
|
|
6302
|
+
});
|
|
6303
|
+
await this.#writeMemoryDreamState(lane.project.projectId, {
|
|
6304
|
+
projectId: String(lane.project.projectId),
|
|
6305
|
+
dirty: true,
|
|
6306
|
+
running: current?.running ?? false,
|
|
6307
|
+
sessionId: String(lane.session.header.sessionId),
|
|
6308
|
+
clientId: String(clientId),
|
|
6309
|
+
lastDailyAppendAt: this.#now(),
|
|
6310
|
+
lastDailyPath: dailyPath,
|
|
6311
|
+
lastFailure: current?.lastFailure,
|
|
6312
|
+
lastSuccessAt: current?.lastSuccessAt,
|
|
6313
|
+
lastProjectMemoryUpdateAt: current?.lastProjectMemoryUpdateAt,
|
|
6314
|
+
lastRootMemoryUpdateAt: current?.lastRootMemoryUpdateAt
|
|
6315
|
+
});
|
|
6316
|
+
}
|
|
5829
6317
|
async #runIdleMemoryDream(projectId) {
|
|
5830
6318
|
const schedule = this.#memoryDreams.get(projectId);
|
|
5831
6319
|
if (!schedule || schedule.running) {
|
|
@@ -5834,10 +6322,28 @@ var init_src4 = __esm({
|
|
|
5834
6322
|
schedule.running = true;
|
|
5835
6323
|
schedule.timer = void 0;
|
|
5836
6324
|
this.#memoryDreams.set(projectId, schedule);
|
|
6325
|
+
const beforeRun = await readMemoryDreamState({
|
|
6326
|
+
projectId,
|
|
6327
|
+
homeDir: this.#memoryHomeDir,
|
|
6328
|
+
now: this.#now
|
|
6329
|
+
});
|
|
6330
|
+
await this.#writeMemoryDreamState(projectId, {
|
|
6331
|
+
...beforeRun ?? { projectId: String(projectId), dirty: true },
|
|
6332
|
+
projectId: String(projectId),
|
|
6333
|
+
running: true,
|
|
6334
|
+
lastAttemptAt: this.#now()
|
|
6335
|
+
});
|
|
5837
6336
|
try {
|
|
5838
6337
|
const lane = await this.#getLane(schedule.sessionId);
|
|
5839
6338
|
const memory = await this.#safeMemorySettingsForRuntime(lane, schedule.clientId);
|
|
5840
6339
|
if (!memory.enabled || !memory.autoDream) {
|
|
6340
|
+
await this.#writeMemoryDreamState(projectId, {
|
|
6341
|
+
...beforeRun ?? { projectId: String(projectId) },
|
|
6342
|
+
projectId: String(projectId),
|
|
6343
|
+
dirty: false,
|
|
6344
|
+
running: false,
|
|
6345
|
+
lastFailure: { at: this.#now(), message: "Memory dream disabled" }
|
|
6346
|
+
});
|
|
5841
6347
|
return;
|
|
5842
6348
|
}
|
|
5843
6349
|
const generated = await this.#generateMemoryUpdate(lane, memory);
|
|
@@ -5860,10 +6366,82 @@ var init_src4 = __esm({
|
|
|
5860
6366
|
path: paths.rootMemoryPath
|
|
5861
6367
|
});
|
|
5862
6368
|
}
|
|
6369
|
+
const now = this.#now();
|
|
6370
|
+
const latestState = await readMemoryDreamState({ projectId, homeDir: this.#memoryHomeDir, now: this.#now });
|
|
6371
|
+
const hasNewDailyDuringRun = latestState?.lastDailyAppendAt !== void 0 && beforeRun?.lastDailyAppendAt !== void 0 && latestState.lastDailyAppendAt > beforeRun.lastDailyAppendAt;
|
|
6372
|
+
await this.#writeMemoryDreamState(projectId, {
|
|
6373
|
+
...latestState ?? { projectId: String(projectId) },
|
|
6374
|
+
projectId: String(projectId),
|
|
6375
|
+
dirty: hasNewDailyDuringRun,
|
|
6376
|
+
running: false,
|
|
6377
|
+
...hasNewDailyDuringRun ? {} : { scheduledFor: void 0 },
|
|
6378
|
+
lastSuccessAt: now,
|
|
6379
|
+
lastFailure: void 0,
|
|
6380
|
+
...generated?.projectMemory?.trim() ? { lastProjectMemoryUpdateAt: now } : {},
|
|
6381
|
+
...memory.promoteRoot && generated?.rootMemory?.trim() ? { lastRootMemoryUpdateAt: now } : {}
|
|
6382
|
+
});
|
|
6383
|
+
if (hasNewDailyDuringRun) {
|
|
6384
|
+
await this.#scheduleMemoryDream(lane, schedule.clientId);
|
|
6385
|
+
}
|
|
6386
|
+
} catch (cause) {
|
|
6387
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
6388
|
+
await this.#writeMemoryDreamState(projectId, {
|
|
6389
|
+
...await readMemoryDreamState({ projectId, homeDir: this.#memoryHomeDir, now: this.#now }) ?? { projectId: String(projectId) },
|
|
6390
|
+
projectId: String(projectId),
|
|
6391
|
+
dirty: true,
|
|
6392
|
+
running: false,
|
|
6393
|
+
lastFailure: { at: this.#now(), message }
|
|
6394
|
+
});
|
|
6395
|
+
throw cause;
|
|
5863
6396
|
} finally {
|
|
5864
6397
|
this.#memoryDreams.delete(projectId);
|
|
5865
6398
|
}
|
|
5866
6399
|
}
|
|
6400
|
+
async #memoryStatusForProject(projectId) {
|
|
6401
|
+
const state = await readMemoryDreamState({
|
|
6402
|
+
projectId,
|
|
6403
|
+
homeDir: this.#memoryHomeDir,
|
|
6404
|
+
now: this.#now
|
|
6405
|
+
});
|
|
6406
|
+
await this.#recoverMemoryDream(projectId, state);
|
|
6407
|
+
const recovered = await readMemoryDreamState({
|
|
6408
|
+
projectId,
|
|
6409
|
+
homeDir: this.#memoryHomeDir,
|
|
6410
|
+
now: this.#now
|
|
6411
|
+
});
|
|
6412
|
+
return {
|
|
6413
|
+
projectId,
|
|
6414
|
+
dirty: recovered?.dirty ?? false,
|
|
6415
|
+
running: recovered?.running ?? false,
|
|
6416
|
+
...recovered?.lastDailyAppendAt !== void 0 ? { lastDailyAppendAt: recovered.lastDailyAppendAt } : {},
|
|
6417
|
+
...recovered?.lastDailyPath ? { lastDailyPath: recovered.lastDailyPath } : {},
|
|
6418
|
+
...recovered?.scheduledFor !== void 0 ? { scheduledFor: recovered.scheduledFor } : {},
|
|
6419
|
+
...recovered?.lastAttemptAt !== void 0 ? { lastAttemptAt: recovered.lastAttemptAt } : {},
|
|
6420
|
+
...recovered?.lastSuccessAt !== void 0 ? { lastSuccessAt: recovered.lastSuccessAt } : {},
|
|
6421
|
+
...recovered?.lastFailure ? { lastFailure: recovered.lastFailure } : {},
|
|
6422
|
+
...recovered?.lastProjectMemoryUpdateAt !== void 0 ? { lastProjectMemoryUpdateAt: recovered.lastProjectMemoryUpdateAt } : {},
|
|
6423
|
+
...recovered?.lastRootMemoryUpdateAt !== void 0 ? { lastRootMemoryUpdateAt: recovered.lastRootMemoryUpdateAt } : {}
|
|
6424
|
+
};
|
|
6425
|
+
}
|
|
6426
|
+
async #recoverMemoryDream(projectId, state) {
|
|
6427
|
+
if (!state?.dirty || this.#memoryDreams.has(projectId)) {
|
|
6428
|
+
return;
|
|
6429
|
+
}
|
|
6430
|
+
const lane = [...this.#sessions.values()].find((candidate) => candidate.project.projectId === projectId);
|
|
6431
|
+
if (!lane) {
|
|
6432
|
+
return;
|
|
6433
|
+
}
|
|
6434
|
+
const clientId = state.clientId ? asClientId(state.clientId) : asClientId("client_memory_recovery");
|
|
6435
|
+
await this.#scheduleMemoryDream(lane, clientId);
|
|
6436
|
+
}
|
|
6437
|
+
async #writeMemoryDreamState(projectId, state) {
|
|
6438
|
+
await writeMemoryDreamState({
|
|
6439
|
+
projectId,
|
|
6440
|
+
homeDir: this.#memoryHomeDir,
|
|
6441
|
+
now: this.#now,
|
|
6442
|
+
state
|
|
6443
|
+
});
|
|
6444
|
+
}
|
|
5867
6445
|
async #generateMemoryUpdate(lane, memory) {
|
|
5868
6446
|
const selectedModel = await this.#selectedModelFromMeta(
|
|
5869
6447
|
{ projectId: lane.project.projectId, modelSelection: { role: "auxiliary" } },
|
|
@@ -6062,7 +6640,7 @@ var init_src4 = __esm({
|
|
|
6062
6640
|
await this.#getLane(sessionId);
|
|
6063
6641
|
return true;
|
|
6064
6642
|
} catch (cause) {
|
|
6065
|
-
if (
|
|
6643
|
+
if (isNodeErrorCode5(cause, "ENOENT")) {
|
|
6066
6644
|
return false;
|
|
6067
6645
|
}
|
|
6068
6646
|
throw cause;
|
|
@@ -6130,13 +6708,17 @@ var init_src4 = __esm({
|
|
|
6130
6708
|
if (!extension) {
|
|
6131
6709
|
throw new Error(`channel_adapter_unavailable: ${current.extensionId}`);
|
|
6132
6710
|
}
|
|
6133
|
-
await extension.adapter.sendMessage(current.target, {
|
|
6711
|
+
await extension.adapter.sendMessage(current.target, {
|
|
6712
|
+
...input.text ? { text: input.text } : {},
|
|
6713
|
+
...input.attachments ? { attachments: input.attachments } : {}
|
|
6714
|
+
});
|
|
6134
6715
|
await this.#appendDiagnostic(lane.session.header.sessionId, "channel_message_sent", {
|
|
6135
6716
|
extensionId: current.extensionId,
|
|
6136
6717
|
channel: current.channel,
|
|
6137
|
-
externalConversationId: current.externalConversationId
|
|
6718
|
+
externalConversationId: current.externalConversationId,
|
|
6719
|
+
attachments: input.attachments?.length ?? 0
|
|
6138
6720
|
});
|
|
6139
|
-
return { channel: current.channel, target: "current" };
|
|
6721
|
+
return { channel: current.channel, target: "current", attachments: input.attachments?.length ?? 0 };
|
|
6140
6722
|
}
|
|
6141
6723
|
})
|
|
6142
6724
|
);
|
|
@@ -6216,7 +6798,7 @@ var init_src4 = __esm({
|
|
|
6216
6798
|
try {
|
|
6217
6799
|
children = await readdir6(root);
|
|
6218
6800
|
} catch (cause) {
|
|
6219
|
-
if (
|
|
6801
|
+
if (isNodeErrorCode5(cause, "ENOENT") || isNodeErrorCode5(cause, "ENOTDIR")) {
|
|
6220
6802
|
continue;
|
|
6221
6803
|
}
|
|
6222
6804
|
throw cause;
|
|
@@ -6305,6 +6887,7 @@ var init_src4 = __esm({
|
|
|
6305
6887
|
externalConversationId,
|
|
6306
6888
|
projectId: project.projectId
|
|
6307
6889
|
});
|
|
6890
|
+
this.#onSessionListChanged?.({ projectId: project.projectId, sessionId });
|
|
6308
6891
|
return binding;
|
|
6309
6892
|
}
|
|
6310
6893
|
async #ensureDefaultWorkspaceProject() {
|
|
@@ -6325,7 +6908,7 @@ var init_src4 = __esm({
|
|
|
6325
6908
|
this.#imBindings.set(imBindingKey(binding.extensionId, binding.externalConversationId), binding);
|
|
6326
6909
|
}
|
|
6327
6910
|
} catch (cause) {
|
|
6328
|
-
if (!
|
|
6911
|
+
if (!isNodeErrorCode5(cause, "ENOENT")) {
|
|
6329
6912
|
throw cause;
|
|
6330
6913
|
}
|
|
6331
6914
|
}
|
|
@@ -6339,9 +6922,13 @@ var init_src4 = __esm({
|
|
|
6339
6922
|
#imBindingsPath() {
|
|
6340
6923
|
return join10(this.#scorelHomeDir, "channels", "im-bindings.json");
|
|
6341
6924
|
}
|
|
6342
|
-
async #loadUserConfigProfile() {
|
|
6925
|
+
async #loadUserConfigProfile(options = {}) {
|
|
6343
6926
|
try {
|
|
6344
|
-
return await loadScorelConfigProfile({
|
|
6927
|
+
return await loadScorelConfigProfile({
|
|
6928
|
+
cwd: this.#userHomeDir,
|
|
6929
|
+
scorelHomeDir: this.#scorelHomeDir,
|
|
6930
|
+
includeSecrets: options.includeSecrets ?? false
|
|
6931
|
+
});
|
|
6345
6932
|
} catch (cause) {
|
|
6346
6933
|
if (isMissingConfigError(cause)) {
|
|
6347
6934
|
return void 0;
|
|
@@ -6349,16 +6936,24 @@ var init_src4 = __esm({
|
|
|
6349
6936
|
throw cause;
|
|
6350
6937
|
}
|
|
6351
6938
|
}
|
|
6939
|
+
#configWriteTarget() {
|
|
6940
|
+
return {
|
|
6941
|
+
configDir: this.#scorelHomeDir,
|
|
6942
|
+
configPath: join10(this.#scorelHomeDir, "config.toml"),
|
|
6943
|
+
workDir: this.#userHomeDir
|
|
6944
|
+
};
|
|
6945
|
+
}
|
|
6352
6946
|
async #listModels(projectId) {
|
|
6353
6947
|
let config;
|
|
6354
6948
|
try {
|
|
6355
|
-
config = await this.#configProfileForProject(projectId);
|
|
6949
|
+
config = projectId ? await this.#configProfileForProject(projectId) : await this.#loadUserConfigProfile();
|
|
6356
6950
|
} catch (cause) {
|
|
6357
6951
|
if (!isMissingConfigError(cause)) {
|
|
6358
6952
|
throw cause;
|
|
6359
6953
|
}
|
|
6360
6954
|
config = void 0;
|
|
6361
6955
|
}
|
|
6956
|
+
config ??= projectId ? void 0 : this.#modelProfile;
|
|
6362
6957
|
if (!config) {
|
|
6363
6958
|
return {
|
|
6364
6959
|
providers: [],
|
|
@@ -6381,19 +6976,18 @@ var init_src4 = __esm({
|
|
|
6381
6976
|
};
|
|
6382
6977
|
}
|
|
6383
6978
|
async #handleUpsertModelProfile(request) {
|
|
6384
|
-
const
|
|
6385
|
-
const configPath = join10(project.workDir, ".scorel", "config.toml");
|
|
6979
|
+
const target = this.#configWriteTarget();
|
|
6386
6980
|
let existingConfigText;
|
|
6387
6981
|
try {
|
|
6388
|
-
existingConfigText = await readFile11(configPath, "utf8");
|
|
6982
|
+
existingConfigText = await readFile11(target.configPath, "utf8");
|
|
6389
6983
|
} catch (cause) {
|
|
6390
|
-
if (!
|
|
6984
|
+
if (!isNodeErrorCode5(cause, "ENOENT")) {
|
|
6391
6985
|
throw cause;
|
|
6392
6986
|
}
|
|
6393
6987
|
}
|
|
6394
|
-
await mkdir6(
|
|
6988
|
+
await mkdir6(target.configDir, { recursive: true });
|
|
6395
6989
|
await writeFile6(
|
|
6396
|
-
configPath,
|
|
6990
|
+
target.configPath,
|
|
6397
6991
|
renderModelProfileConfig({
|
|
6398
6992
|
providerId: request.providerId,
|
|
6399
6993
|
providerType: request.providerType,
|
|
@@ -6420,15 +7014,41 @@ var init_src4 = __esm({
|
|
|
6420
7014
|
"utf8"
|
|
6421
7015
|
);
|
|
6422
7016
|
await this.#appendHostDiagnostic("model_profile_upserted", {
|
|
6423
|
-
projectId:
|
|
6424
|
-
|
|
7017
|
+
...request.projectId ? { ignoredProjectId: request.projectId } : {},
|
|
7018
|
+
scope: "device",
|
|
7019
|
+
workDir: target.workDir,
|
|
6425
7020
|
providerId: request.providerId,
|
|
6426
7021
|
modelId: request.modelId
|
|
6427
7022
|
});
|
|
6428
|
-
return this.#listModels(
|
|
7023
|
+
return this.#listModels();
|
|
7024
|
+
}
|
|
7025
|
+
async #handleRemoveModelProvider(request) {
|
|
7026
|
+
const target = this.#configWriteTarget();
|
|
7027
|
+
let existingConfigText;
|
|
7028
|
+
try {
|
|
7029
|
+
existingConfigText = await readFile11(target.configPath, "utf8");
|
|
7030
|
+
} catch (cause) {
|
|
7031
|
+
if (!isNodeErrorCode5(cause, "ENOENT")) {
|
|
7032
|
+
throw cause;
|
|
7033
|
+
}
|
|
7034
|
+
}
|
|
7035
|
+
await mkdir6(target.configDir, { recursive: true });
|
|
7036
|
+
await writeFile6(
|
|
7037
|
+
target.configPath,
|
|
7038
|
+
renderModelProfileConfig({
|
|
7039
|
+
removeProviderId: request.providerId,
|
|
7040
|
+
existingConfigText
|
|
7041
|
+
}),
|
|
7042
|
+
"utf8"
|
|
7043
|
+
);
|
|
7044
|
+
const profile = await this.#listModels();
|
|
7045
|
+
return { ...profile, removed: true };
|
|
6429
7046
|
}
|
|
6430
7047
|
async #memorySettingsForProject(projectId) {
|
|
6431
|
-
|
|
7048
|
+
return this.#memorySettings(projectId);
|
|
7049
|
+
}
|
|
7050
|
+
async #memorySettings(projectId) {
|
|
7051
|
+
const config = await (projectId ? this.#configProfileForProject(projectId) : this.#loadUserConfigProfile()).catch((cause) => {
|
|
6432
7052
|
if (isMissingConfigError(cause)) {
|
|
6433
7053
|
return void 0;
|
|
6434
7054
|
}
|
|
@@ -6450,19 +7070,18 @@ var init_src4 = __esm({
|
|
|
6450
7070
|
}
|
|
6451
7071
|
}
|
|
6452
7072
|
async #handleUpsertMemorySettings(request) {
|
|
6453
|
-
const
|
|
6454
|
-
const configPath = join10(project.workDir, ".scorel", "config.toml");
|
|
7073
|
+
const target = this.#configWriteTarget();
|
|
6455
7074
|
let existingConfigText;
|
|
6456
7075
|
try {
|
|
6457
|
-
existingConfigText = await readFile11(configPath, "utf8");
|
|
7076
|
+
existingConfigText = await readFile11(target.configPath, "utf8");
|
|
6458
7077
|
} catch (cause) {
|
|
6459
|
-
if (!
|
|
7078
|
+
if (!isNodeErrorCode5(cause, "ENOENT")) {
|
|
6460
7079
|
throw cause;
|
|
6461
7080
|
}
|
|
6462
7081
|
}
|
|
6463
|
-
await mkdir6(
|
|
7082
|
+
await mkdir6(target.configDir, { recursive: true });
|
|
6464
7083
|
await writeFile6(
|
|
6465
|
-
configPath,
|
|
7084
|
+
target.configPath,
|
|
6466
7085
|
renderMemoryConfig({
|
|
6467
7086
|
enabled: request.enabled,
|
|
6468
7087
|
daily: request.daily,
|
|
@@ -6476,10 +7095,66 @@ var init_src4 = __esm({
|
|
|
6476
7095
|
"utf8"
|
|
6477
7096
|
);
|
|
6478
7097
|
await this.#appendHostDiagnostic("memory_settings_upserted", {
|
|
6479
|
-
projectId:
|
|
6480
|
-
|
|
7098
|
+
...request.projectId ? { ignoredProjectId: request.projectId } : {},
|
|
7099
|
+
scope: "device",
|
|
7100
|
+
workDir: target.workDir
|
|
7101
|
+
});
|
|
7102
|
+
return this.#memorySettings();
|
|
7103
|
+
}
|
|
7104
|
+
async #runtimeSettingsForProject(projectId, installStatus) {
|
|
7105
|
+
return this.#runtimeSettings(projectId, installStatus);
|
|
7106
|
+
}
|
|
7107
|
+
async #runtimeSettings(projectId, installStatus) {
|
|
7108
|
+
const config = await (projectId ? this.#configProfileForProject(projectId) : this.#loadUserConfigProfile()).catch((cause) => {
|
|
7109
|
+
if (isMissingConfigError(cause)) {
|
|
7110
|
+
return void 0;
|
|
7111
|
+
}
|
|
7112
|
+
throw cause;
|
|
7113
|
+
});
|
|
7114
|
+
const detected = await detectRtk();
|
|
7115
|
+
const savings = await readRuntimeStats(this.#runtimeStatsPath());
|
|
7116
|
+
return {
|
|
7117
|
+
tokenSavingRtk: config?.runtime.tokenSavingRtk ?? false,
|
|
7118
|
+
rtkAvailable: detected.available,
|
|
7119
|
+
...detected.executable ? { rtkExecutable: detected.executable } : {},
|
|
7120
|
+
...detected.version ? { rtkVersion: detected.version } : {},
|
|
7121
|
+
...installStatus?.installStatus ? { installStatus: installStatus.installStatus } : {},
|
|
7122
|
+
...installStatus?.installMessage ? { installMessage: installStatus.installMessage } : {},
|
|
7123
|
+
estimatedOutputTokens: savings.rtk.outputTokens,
|
|
7124
|
+
estimatedSavedTokens: savings.rtk.savedTokens
|
|
7125
|
+
};
|
|
7126
|
+
}
|
|
7127
|
+
async #handleUpsertRuntimeSettings(request) {
|
|
7128
|
+
const target = this.#configWriteTarget();
|
|
7129
|
+
let existingConfigText;
|
|
7130
|
+
try {
|
|
7131
|
+
existingConfigText = await readFile11(target.configPath, "utf8");
|
|
7132
|
+
} catch (cause) {
|
|
7133
|
+
if (!isNodeErrorCode5(cause, "ENOENT")) {
|
|
7134
|
+
throw cause;
|
|
7135
|
+
}
|
|
7136
|
+
}
|
|
7137
|
+
await mkdir6(target.configDir, { recursive: true });
|
|
7138
|
+
await writeFile6(
|
|
7139
|
+
target.configPath,
|
|
7140
|
+
renderRuntimeConfig({
|
|
7141
|
+
tokenSavingRtk: request.tokenSavingRtk,
|
|
7142
|
+
existingConfigText
|
|
7143
|
+
}),
|
|
7144
|
+
"utf8"
|
|
7145
|
+
);
|
|
7146
|
+
const installResult = request.tokenSavingRtk === true ? await ensureRtkAvailable() : { status: "idle" };
|
|
7147
|
+
await this.#appendHostDiagnostic("runtime_settings_upserted", {
|
|
7148
|
+
...request.projectId ? { ignoredProjectId: request.projectId } : {},
|
|
7149
|
+
scope: "device",
|
|
7150
|
+
workDir: target.workDir,
|
|
7151
|
+
tokenSavingRtk: request.tokenSavingRtk,
|
|
7152
|
+
installStatus: installResult.status
|
|
7153
|
+
});
|
|
7154
|
+
return this.#runtimeSettings(void 0, {
|
|
7155
|
+
installStatus: installResult.status,
|
|
7156
|
+
...installResult.message ? { installMessage: installResult.message } : {}
|
|
6481
7157
|
});
|
|
6482
|
-
return this.#memorySettingsForProject(project.projectId);
|
|
6483
7158
|
}
|
|
6484
7159
|
async #extensionSettings(extensionId) {
|
|
6485
7160
|
const config = await this.#loadUserConfigProfile().catch((cause) => {
|
|
@@ -6503,7 +7178,7 @@ var init_src4 = __esm({
|
|
|
6503
7178
|
try {
|
|
6504
7179
|
existingConfigText = await readFile11(configPath, "utf8");
|
|
6505
7180
|
} catch (cause) {
|
|
6506
|
-
if (!
|
|
7181
|
+
if (!isNodeErrorCode5(cause, "ENOENT")) {
|
|
6507
7182
|
throw cause;
|
|
6508
7183
|
}
|
|
6509
7184
|
}
|
|
@@ -6527,8 +7202,11 @@ var init_src4 = __esm({
|
|
|
6527
7202
|
return this.#extensionSettings(request.extensionId);
|
|
6528
7203
|
}
|
|
6529
7204
|
async #fetchProviderModels(projectId, providerId) {
|
|
6530
|
-
const
|
|
6531
|
-
|
|
7205
|
+
const config = projectId ? await loadScorelConfigProfile({
|
|
7206
|
+
cwd: (await this.#registry.require(projectId)).workDir,
|
|
7207
|
+
scorelHomeDir: this.#scorelHomeDir,
|
|
7208
|
+
includeSecrets: true
|
|
7209
|
+
}) : await this.#loadUserConfigProfile({ includeSecrets: true });
|
|
6532
7210
|
if (!config) {
|
|
6533
7211
|
throw new Error("Model profile config is not configured");
|
|
6534
7212
|
}
|
|
@@ -6613,7 +7291,7 @@ var init_src4 = __esm({
|
|
|
6613
7291
|
}
|
|
6614
7292
|
const project = await this.#registry.require(projectId);
|
|
6615
7293
|
try {
|
|
6616
|
-
return await loadScorelConfigProfile({ cwd: project.workDir });
|
|
7294
|
+
return await loadScorelConfigProfile({ cwd: project.workDir, scorelHomeDir: this.#scorelHomeDir });
|
|
6617
7295
|
} catch (cause) {
|
|
6618
7296
|
if (!isMissingConfigError(cause)) {
|
|
6619
7297
|
throw cause;
|
|
@@ -6654,6 +7332,20 @@ var init_src4 = __esm({
|
|
|
6654
7332
|
await appendFile3(join10(this.#sessionsDir, "host.log"), `${line}
|
|
6655
7333
|
`, "utf8");
|
|
6656
7334
|
}
|
|
7335
|
+
#runtimeStatsPath() {
|
|
7336
|
+
return join10(this.#scorelHomeDir, "runtime-stats.json");
|
|
7337
|
+
}
|
|
7338
|
+
async #recordRtkSavings(input) {
|
|
7339
|
+
const updateTask = this.#runtimeStatsQueue.then(async () => {
|
|
7340
|
+
const path = this.#runtimeStatsPath();
|
|
7341
|
+
const stats = await readRuntimeStats(path);
|
|
7342
|
+
addRtkSavings(stats, String(input.projectId), String(input.sessionId), input.savings);
|
|
7343
|
+
await writeRuntimeStats(path, stats);
|
|
7344
|
+
});
|
|
7345
|
+
this.#runtimeStatsQueue = updateTask.catch(() => {
|
|
7346
|
+
});
|
|
7347
|
+
await updateTask;
|
|
7348
|
+
}
|
|
6657
7349
|
async #resolveProject(sessionId, projectId) {
|
|
6658
7350
|
const project = await this.#registry.require(projectId);
|
|
6659
7351
|
await this.#appendDiagnostic(sessionId, "project_resolved", {
|
|
@@ -6709,7 +7401,7 @@ var init_src4 = __esm({
|
|
|
6709
7401
|
}
|
|
6710
7402
|
};
|
|
6711
7403
|
};
|
|
6712
|
-
|
|
7404
|
+
isNodeErrorCode5 = (cause, code) => cause instanceof Error && "code" in cause && cause.code === code;
|
|
6713
7405
|
wireErrorCode = (cause) => {
|
|
6714
7406
|
if (!(cause instanceof ProjectRegistryError)) {
|
|
6715
7407
|
return "internal_error";
|
|
@@ -6760,7 +7452,7 @@ var init_src4 = __esm({
|
|
|
6760
7452
|
return void 0;
|
|
6761
7453
|
}
|
|
6762
7454
|
const parsed = JSON.parse(text);
|
|
6763
|
-
if (!
|
|
7455
|
+
if (!isRecord8(parsed)) {
|
|
6764
7456
|
return void 0;
|
|
6765
7457
|
}
|
|
6766
7458
|
return {
|
|
@@ -6780,6 +7472,147 @@ var init_src4 = __esm({
|
|
|
6780
7472
|
dreamIdleMinutes: 60,
|
|
6781
7473
|
autoCompactThreshold: 0.8
|
|
6782
7474
|
});
|
|
7475
|
+
detectRtk = async () => {
|
|
7476
|
+
try {
|
|
7477
|
+
const shell = resolveDefaultShell2();
|
|
7478
|
+
const path = (await execFileAsync2(shell, shellCommandArgs2(shell, "command -v rtk"), { timeout: 5e3 })).stdout.trim();
|
|
7479
|
+
if (!path) {
|
|
7480
|
+
return { available: false };
|
|
7481
|
+
}
|
|
7482
|
+
const version = await execFileAsync2(path, ["--version"], { timeout: 5e3 }).then((result) => result.stdout.trim() || result.stderr.trim()).catch(() => void 0);
|
|
7483
|
+
return {
|
|
7484
|
+
available: true,
|
|
7485
|
+
executable: path,
|
|
7486
|
+
...version ? { version } : {}
|
|
7487
|
+
};
|
|
7488
|
+
} catch {
|
|
7489
|
+
return { available: false };
|
|
7490
|
+
}
|
|
7491
|
+
};
|
|
7492
|
+
ensureRtkAvailable = async () => {
|
|
7493
|
+
const existing = await detectRtk();
|
|
7494
|
+
if (existing.available) {
|
|
7495
|
+
return { status: "installed", message: existing.version ?? existing.executable };
|
|
7496
|
+
}
|
|
7497
|
+
const shell = resolveDefaultShell2();
|
|
7498
|
+
const brew = await execFileAsync2(shell, shellCommandArgs2(shell, "command -v brew"), { timeout: 5e3 }).then((result) => result.stdout.trim()).catch(() => "");
|
|
7499
|
+
if (!brew) {
|
|
7500
|
+
return { status: "failed", message: "Homebrew is not available; install RTK manually with `brew install rtk`." };
|
|
7501
|
+
}
|
|
7502
|
+
try {
|
|
7503
|
+
await execFileAsync2(brew, ["install", "rtk"], { timeout: 12e4, maxBuffer: 2e7 });
|
|
7504
|
+
const installed = await detectRtk();
|
|
7505
|
+
return installed.available ? { status: "installed", message: installed.version ?? installed.executable } : { status: "failed", message: "RTK install finished but `rtk` is still not on PATH." };
|
|
7506
|
+
} catch (cause) {
|
|
7507
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
7508
|
+
return { status: "failed", message };
|
|
7509
|
+
}
|
|
7510
|
+
};
|
|
7511
|
+
emptyRuntimeStats = () => ({
|
|
7512
|
+
version: 1,
|
|
7513
|
+
rtk: {
|
|
7514
|
+
outputTokens: 0,
|
|
7515
|
+
savedTokens: 0,
|
|
7516
|
+
byProject: {},
|
|
7517
|
+
bySession: {}
|
|
7518
|
+
}
|
|
7519
|
+
});
|
|
7520
|
+
readRuntimeStats = async (path) => {
|
|
7521
|
+
try {
|
|
7522
|
+
return parseRuntimeStats(JSON.parse(await readFile11(path, "utf8")));
|
|
7523
|
+
} catch (cause) {
|
|
7524
|
+
if (isNodeErrorCode5(cause, "ENOENT")) {
|
|
7525
|
+
return emptyRuntimeStats();
|
|
7526
|
+
}
|
|
7527
|
+
return emptyRuntimeStats();
|
|
7528
|
+
}
|
|
7529
|
+
};
|
|
7530
|
+
writeRuntimeStats = async (path, stats) => {
|
|
7531
|
+
await mkdir6(dirname8(path), { recursive: true });
|
|
7532
|
+
const tempPath = join10(dirname8(path), `.runtime-stats-${process.pid}-${Date.now()}.tmp`);
|
|
7533
|
+
try {
|
|
7534
|
+
await writeFile6(tempPath, `${JSON.stringify(stats, null, 2)}
|
|
7535
|
+
`, "utf8");
|
|
7536
|
+
await rename3(tempPath, path);
|
|
7537
|
+
} catch (cause) {
|
|
7538
|
+
await rm2(tempPath, { force: true }).catch(() => void 0);
|
|
7539
|
+
throw cause;
|
|
7540
|
+
}
|
|
7541
|
+
};
|
|
7542
|
+
parseRuntimeStats = (value) => {
|
|
7543
|
+
if (!isRecord8(value) || !isRecord8(value.rtk)) {
|
|
7544
|
+
return emptyRuntimeStats();
|
|
7545
|
+
}
|
|
7546
|
+
return {
|
|
7547
|
+
version: 1,
|
|
7548
|
+
rtk: {
|
|
7549
|
+
outputTokens: nonNegativeInteger2(value.rtk.outputTokens),
|
|
7550
|
+
savedTokens: nonNegativeInteger2(value.rtk.savedTokens),
|
|
7551
|
+
byProject: parseRuntimeStatsBuckets(value.rtk.byProject),
|
|
7552
|
+
bySession: parseRuntimeStatsBuckets(value.rtk.bySession)
|
|
7553
|
+
}
|
|
7554
|
+
};
|
|
7555
|
+
};
|
|
7556
|
+
parseRuntimeStatsBuckets = (value) => {
|
|
7557
|
+
if (!isRecord8(value)) {
|
|
7558
|
+
return {};
|
|
7559
|
+
}
|
|
7560
|
+
return Object.fromEntries(
|
|
7561
|
+
Object.entries(value).map(([key, bucket]) => [
|
|
7562
|
+
key,
|
|
7563
|
+
isRecord8(bucket) ? {
|
|
7564
|
+
outputTokens: nonNegativeInteger2(bucket.outputTokens),
|
|
7565
|
+
savedTokens: nonNegativeInteger2(bucket.savedTokens)
|
|
7566
|
+
} : { outputTokens: 0, savedTokens: 0 }
|
|
7567
|
+
])
|
|
7568
|
+
);
|
|
7569
|
+
};
|
|
7570
|
+
addRtkSavings = (stats, projectId, sessionId, savings) => {
|
|
7571
|
+
addRuntimeStatsBucket(stats.rtk, savings);
|
|
7572
|
+
stats.rtk.byProject[projectId] = addRuntimeStatsBucket(stats.rtk.byProject[projectId] ?? { outputTokens: 0, savedTokens: 0 }, savings);
|
|
7573
|
+
stats.rtk.bySession[sessionId] = addRuntimeStatsBucket(stats.rtk.bySession[sessionId] ?? { outputTokens: 0, savedTokens: 0 }, savings);
|
|
7574
|
+
};
|
|
7575
|
+
addRuntimeStatsBucket = (bucket, savings) => {
|
|
7576
|
+
bucket.outputTokens += savings.outputTokens;
|
|
7577
|
+
bucket.savedTokens += savings.savedTokens;
|
|
7578
|
+
return bucket;
|
|
7579
|
+
};
|
|
7580
|
+
rtkSavingsFromToolResult = (result) => {
|
|
7581
|
+
if (!isRecord8(result) || !isRecord8(result.details)) {
|
|
7582
|
+
return void 0;
|
|
7583
|
+
}
|
|
7584
|
+
const rtk = result.details.rtk;
|
|
7585
|
+
if (!isRecord8(rtk) || rtk.applied !== true) {
|
|
7586
|
+
return void 0;
|
|
7587
|
+
}
|
|
7588
|
+
const outputTokens = nonNegativeInteger2(rtk.estimatedOutputTokens);
|
|
7589
|
+
const savedTokens = nonNegativeInteger2(rtk.estimatedSavedTokens);
|
|
7590
|
+
return outputTokens > 0 || savedTokens > 0 ? { outputTokens, savedTokens } : void 0;
|
|
7591
|
+
};
|
|
7592
|
+
nonNegativeInteger2 = (value) => {
|
|
7593
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
7594
|
+
return 0;
|
|
7595
|
+
}
|
|
7596
|
+
return Math.floor(value);
|
|
7597
|
+
};
|
|
7598
|
+
resolveDefaultShell2 = () => {
|
|
7599
|
+
const shell = process.env.SHELL || userShell2() || "/bin/sh";
|
|
7600
|
+
return shell.trim() || "/bin/sh";
|
|
7601
|
+
};
|
|
7602
|
+
shellCommandArgs2 = (shell, command) => {
|
|
7603
|
+
const name = basename3(shell).toLowerCase();
|
|
7604
|
+
if (name === "csh" || name === "tcsh" || name === "fish") {
|
|
7605
|
+
return ["-c", command];
|
|
7606
|
+
}
|
|
7607
|
+
return ["-lc", command];
|
|
7608
|
+
};
|
|
7609
|
+
userShell2 = () => {
|
|
7610
|
+
try {
|
|
7611
|
+
return userInfo2().shell ?? void 0;
|
|
7612
|
+
} catch {
|
|
7613
|
+
return void 0;
|
|
7614
|
+
}
|
|
7615
|
+
};
|
|
6783
7616
|
runtimeChannelContextFromWire = (context) => ({
|
|
6784
7617
|
extensionId: context.channel,
|
|
6785
7618
|
channel: context.channel,
|
|
@@ -6794,7 +7627,7 @@ var init_src4 = __esm({
|
|
|
6794
7627
|
...context.data ? { data: context.data } : {}
|
|
6795
7628
|
});
|
|
6796
7629
|
parseQueuedChannelContext = (value) => {
|
|
6797
|
-
if (!
|
|
7630
|
+
if (!isRecord8(value)) {
|
|
6798
7631
|
return void 0;
|
|
6799
7632
|
}
|
|
6800
7633
|
if (typeof value.channel !== "string" || typeof value.externalConversationId !== "string") {
|
|
@@ -6806,7 +7639,7 @@ var init_src4 = __esm({
|
|
|
6806
7639
|
...typeof value.conversationType === "string" ? { conversationType: value.conversationType } : {},
|
|
6807
7640
|
...typeof value.senderDisplayName === "string" ? { senderDisplayName: value.senderDisplayName } : {},
|
|
6808
7641
|
...typeof value.mentionedBot === "boolean" ? { mentionedBot: value.mentionedBot } : {},
|
|
6809
|
-
...
|
|
7642
|
+
...isRecord8(value.data) ? { data: value.data } : {}
|
|
6810
7643
|
});
|
|
6811
7644
|
};
|
|
6812
7645
|
imBindingKey = (extensionId, externalConversationId) => `${extensionId}:${externalConversationId}`;
|
|
@@ -6839,7 +7672,7 @@ var init_src4 = __esm({
|
|
|
6839
7672
|
};
|
|
6840
7673
|
isSteerMessage = (text) => /^\/(?:steer|interrupt)\b/i.test(text.trim());
|
|
6841
7674
|
stripImCommandPrefix = (text) => text.trim().replace(/^\/(?:steer|interrupt)\s*/i, "").trim() || text;
|
|
6842
|
-
|
|
7675
|
+
isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6843
7676
|
parseMemoryUpdate = (raw) => {
|
|
6844
7677
|
const text = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
6845
7678
|
if (!text) {
|
|
@@ -6946,9 +7779,11 @@ var init_relay_cli = __esm({
|
|
|
6946
7779
|
|
|
6947
7780
|
// apps/cli/src/daemon-cli.ts
|
|
6948
7781
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
7782
|
+
import { spawn } from "node:child_process";
|
|
6949
7783
|
import { homedir as homedir6 } from "node:os";
|
|
6950
|
-
import { join as join12 } from "node:path";
|
|
6951
|
-
|
|
7784
|
+
import { dirname as dirname9, join as join12 } from "node:path";
|
|
7785
|
+
import { fileURLToPath } from "node:url";
|
|
7786
|
+
var DEFAULT_HOST, DEFAULT_PORT, STOP_POLL_INTERVAL_MS, STOP_GRACE_MS, START_READY_TIMEOUT_MS, DEFAULT_IDLE_SHUTDOWN_MS, defaultStateDir2, isLoopbackHost, formatTimestamp, runCliDaemon, runStartCommand, runServeCommand, stopRunningDaemon, runStatusCommand, runStopCommand, runResetCommand, formatStatusLine, parseServeFlags, parseStatusFlags, requireValue2, sleep, waitForDaemonReady, detachBackgroundDaemon, nodeEntrypointArgs, writeDaemonUsage;
|
|
6952
7787
|
var init_daemon_cli = __esm({
|
|
6953
7788
|
"apps/cli/src/daemon-cli.ts"() {
|
|
6954
7789
|
"use strict";
|
|
@@ -6958,6 +7793,8 @@ var init_daemon_cli = __esm({
|
|
|
6958
7793
|
DEFAULT_PORT = 7777;
|
|
6959
7794
|
STOP_POLL_INTERVAL_MS = 200;
|
|
6960
7795
|
STOP_GRACE_MS = 5e3;
|
|
7796
|
+
START_READY_TIMEOUT_MS = 1e4;
|
|
7797
|
+
DEFAULT_IDLE_SHUTDOWN_MS = 15 * 60 * 1e3;
|
|
6961
7798
|
defaultStateDir2 = () => join12(homedir6(), ".scorel");
|
|
6962
7799
|
isLoopbackHost = (host) => host === "127.0.0.1" || host === "::1" || host === "localhost";
|
|
6963
7800
|
formatTimestamp = (epochMs) => new Date(epochMs).toISOString();
|
|
@@ -6965,6 +7802,8 @@ var init_daemon_cli = __esm({
|
|
|
6965
7802
|
const [command, ...rest] = argv;
|
|
6966
7803
|
const stateDir = options.stateDir ?? defaultStateDir2();
|
|
6967
7804
|
switch (command) {
|
|
7805
|
+
case "start":
|
|
7806
|
+
return runStartCommand(rest, { ...options, stateDir });
|
|
6968
7807
|
case "serve":
|
|
6969
7808
|
return runServeCommand(rest, { ...options, stateDir });
|
|
6970
7809
|
case "status":
|
|
@@ -6982,6 +7821,63 @@ var init_daemon_cli = __esm({
|
|
|
6982
7821
|
return 1;
|
|
6983
7822
|
}
|
|
6984
7823
|
};
|
|
7824
|
+
runStartCommand = async (argv, options) => {
|
|
7825
|
+
let flags;
|
|
7826
|
+
try {
|
|
7827
|
+
flags = parseServeFlags(argv, options.cwd ?? process.cwd(), options.env ?? process.env);
|
|
7828
|
+
} catch (cause) {
|
|
7829
|
+
options.error.write(`scorel daemon start error: ${cause.message}
|
|
7830
|
+
`);
|
|
7831
|
+
return 1;
|
|
7832
|
+
}
|
|
7833
|
+
const readState = options.readState ?? ((stateDir) => readLocalDaemonState({ stateDir }));
|
|
7834
|
+
const existing = await readState(options.stateDir);
|
|
7835
|
+
if (existing && daemonStateLiveness(existing) === "running") {
|
|
7836
|
+
options.output.write(`scorel host already running url=${existing.wsUrl} pid=${existing.pid}
|
|
7837
|
+
`);
|
|
7838
|
+
return 0;
|
|
7839
|
+
}
|
|
7840
|
+
const cliEntrypoint = options.cliEntrypoint ?? fileURLToPath(import.meta.url).replace(/daemon-cli\.ts$/, "index.ts");
|
|
7841
|
+
const child = (options.spawn ?? spawn)(process.execPath, [
|
|
7842
|
+
...nodeEntrypointArgs(cliEntrypoint),
|
|
7843
|
+
"host",
|
|
7844
|
+
"serve",
|
|
7845
|
+
"--host",
|
|
7846
|
+
flags.host,
|
|
7847
|
+
"--port",
|
|
7848
|
+
String(flags.port),
|
|
7849
|
+
"--cwd",
|
|
7850
|
+
flags.cwd,
|
|
7851
|
+
"--idle-timeout-ms",
|
|
7852
|
+
String(flags.idleShutdownMs),
|
|
7853
|
+
...flags.token ? ["--token", flags.token] : [],
|
|
7854
|
+
...flags.relayUrl ? ["--relay", flags.relayUrl] : ["--no-relay"],
|
|
7855
|
+
...flags.replace ? ["--replace"] : []
|
|
7856
|
+
], {
|
|
7857
|
+
cwd: dirname9(cliEntrypoint),
|
|
7858
|
+
env: { ...process.env, ...options.env ?? {} },
|
|
7859
|
+
detached: true,
|
|
7860
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
7861
|
+
});
|
|
7862
|
+
try {
|
|
7863
|
+
await waitForDaemonReady(child, options.daemonReadyTimeoutMs ?? START_READY_TIMEOUT_MS);
|
|
7864
|
+
} catch (cause) {
|
|
7865
|
+
options.error.write(`scorel daemon start error: ${cause.message}
|
|
7866
|
+
`);
|
|
7867
|
+
child.kill("SIGTERM");
|
|
7868
|
+
return 1;
|
|
7869
|
+
}
|
|
7870
|
+
const state = await readState(options.stateDir);
|
|
7871
|
+
if (!state || daemonStateLiveness(state) !== "running") {
|
|
7872
|
+
options.error.write("scorel daemon start error: daemon state missing after start\n");
|
|
7873
|
+
child.kill("SIGTERM");
|
|
7874
|
+
return 1;
|
|
7875
|
+
}
|
|
7876
|
+
detachBackgroundDaemon(child);
|
|
7877
|
+
options.output.write(`scorel host started url=${state.wsUrl} pid=${state.pid}
|
|
7878
|
+
`);
|
|
7879
|
+
return 0;
|
|
7880
|
+
};
|
|
6985
7881
|
runServeCommand = async (argv, options) => {
|
|
6986
7882
|
let flags;
|
|
6987
7883
|
try {
|
|
@@ -7009,16 +7905,28 @@ Use --replace to stop it and start a new one.
|
|
|
7009
7905
|
}
|
|
7010
7906
|
const token = flags.token ?? existing?.token ?? randomUUID4();
|
|
7011
7907
|
const identity = await loadOrCreateHostDeviceIdentity({ stateDir: options.stateDir });
|
|
7908
|
+
const configScope = { scorelHomeDir: options.stateDir };
|
|
7909
|
+
let signalReason = "natural";
|
|
7910
|
+
let resolveStopWaiter;
|
|
7911
|
+
let stopRequested = false;
|
|
7912
|
+
const requestStop = (reason) => {
|
|
7913
|
+
signalReason = reason;
|
|
7914
|
+
stopRequested = true;
|
|
7915
|
+
resolveStopWaiter?.();
|
|
7916
|
+
};
|
|
7012
7917
|
const daemon = new ScorelHost({
|
|
7013
7918
|
sessionsDir: options.sessionsDir ?? scorelSessionsDir(homedir6()),
|
|
7014
7919
|
projectsPath: join12(options.stateDir, "projects.json"),
|
|
7015
7920
|
deviceId: identity.deviceId,
|
|
7016
7921
|
deviceDisplayName: identity.displayName,
|
|
7017
|
-
|
|
7018
|
-
|
|
7922
|
+
idleShutdownMs: flags.idleShutdownMs,
|
|
7923
|
+
onIdleShutdown: () => requestStop("idle"),
|
|
7924
|
+
scorelHomeDir: options.stateDir,
|
|
7925
|
+
loadConfig: async ({ project }) => loadScorelConfig({ cwd: project.workDir, ...configScope }),
|
|
7926
|
+
loadConfigProfile: async ({ project }) => loadScorelConfigProfile({ cwd: project.workDir, ...configScope }),
|
|
7019
7927
|
createRuntime: async ({ project, selectedModel, purpose }) => createRealRuntime({
|
|
7020
7928
|
cwd: project.workDir,
|
|
7021
|
-
config: await loadScorelConfig({ cwd: project.workDir }),
|
|
7929
|
+
config: await loadScorelConfig({ cwd: project.workDir, ...configScope }),
|
|
7022
7930
|
modelSelection: selectedModel ? { modelId: selectedModel.modelId, role: selectedModel.role } : void 0,
|
|
7023
7931
|
includeTools: purpose === "chat"
|
|
7024
7932
|
})
|
|
@@ -7077,20 +7985,22 @@ Use --replace to stop it and start a new one.
|
|
|
7077
7985
|
await markDaemonStopped({ stateDir: options.stateDir, stoppedAt: Date.now() });
|
|
7078
7986
|
}
|
|
7079
7987
|
};
|
|
7080
|
-
let signalReason = "natural";
|
|
7081
7988
|
const signalHandlers = /* @__PURE__ */ new Map();
|
|
7082
7989
|
const stopWaiter = new Promise((resolve7) => {
|
|
7990
|
+
resolveStopWaiter = resolve7;
|
|
7991
|
+
if (stopRequested) {
|
|
7992
|
+
resolve7();
|
|
7993
|
+
return;
|
|
7994
|
+
}
|
|
7083
7995
|
if (options.serveSignal) {
|
|
7084
7996
|
if (options.serveSignal.aborted) {
|
|
7085
|
-
|
|
7086
|
-
resolve7();
|
|
7997
|
+
requestStop("abort");
|
|
7087
7998
|
return;
|
|
7088
7999
|
}
|
|
7089
8000
|
options.serveSignal.addEventListener(
|
|
7090
8001
|
"abort",
|
|
7091
8002
|
() => {
|
|
7092
|
-
|
|
7093
|
-
resolve7();
|
|
8003
|
+
requestStop("abort");
|
|
7094
8004
|
},
|
|
7095
8005
|
{ once: true }
|
|
7096
8006
|
);
|
|
@@ -7098,8 +8008,7 @@ Use --replace to stop it and start a new one.
|
|
|
7098
8008
|
}
|
|
7099
8009
|
const installSignal = (signal) => {
|
|
7100
8010
|
const handler = () => {
|
|
7101
|
-
|
|
7102
|
-
resolve7();
|
|
8011
|
+
requestStop(signal);
|
|
7103
8012
|
};
|
|
7104
8013
|
signalHandlers.set(signal, handler);
|
|
7105
8014
|
process.once(signal, handler);
|
|
@@ -7229,6 +8138,7 @@ Use --replace to stop it and start a new one.
|
|
|
7229
8138
|
let token;
|
|
7230
8139
|
let relayUrl = resolveDefaultRelayUrl(env);
|
|
7231
8140
|
let replace = false;
|
|
8141
|
+
let idleShutdownMs = DEFAULT_IDLE_SHUTDOWN_MS;
|
|
7232
8142
|
for (let index = 0; index < argv.length; index += 1) {
|
|
7233
8143
|
const arg = argv[index];
|
|
7234
8144
|
if (arg === "--host") {
|
|
@@ -7272,9 +8182,17 @@ Use --replace to stop it and start a new one.
|
|
|
7272
8182
|
replace = true;
|
|
7273
8183
|
continue;
|
|
7274
8184
|
}
|
|
8185
|
+
if (arg === "--idle-timeout-ms") {
|
|
8186
|
+
idleShutdownMs = Number(requireValue2(argv, index, "--idle-timeout-ms"));
|
|
8187
|
+
if (!Number.isInteger(idleShutdownMs) || idleShutdownMs < 0) {
|
|
8188
|
+
throw new Error("--idle-timeout-ms must be a non-negative integer");
|
|
8189
|
+
}
|
|
8190
|
+
index += 1;
|
|
8191
|
+
continue;
|
|
8192
|
+
}
|
|
7275
8193
|
throw new Error(`Unknown serve option: ${arg}`);
|
|
7276
8194
|
}
|
|
7277
|
-
return { host, port, token, cwd, relayUrl, replace };
|
|
8195
|
+
return { host, port, token, cwd, relayUrl, replace, idleShutdownMs };
|
|
7278
8196
|
};
|
|
7279
8197
|
parseStatusFlags = (argv) => {
|
|
7280
8198
|
let showToken = false;
|
|
@@ -7297,11 +8215,66 @@ Use --replace to stop it and start a new one.
|
|
|
7297
8215
|
sleep = (ms) => new Promise((resolve7) => {
|
|
7298
8216
|
setTimeout(resolve7, ms);
|
|
7299
8217
|
});
|
|
8218
|
+
waitForDaemonReady = (child, timeoutMs) => new Promise((resolveReady, rejectReady) => {
|
|
8219
|
+
if (!child.stdout) {
|
|
8220
|
+
rejectReady(new Error("daemon child has no stdout stream"));
|
|
8221
|
+
return;
|
|
8222
|
+
}
|
|
8223
|
+
let buffer = "";
|
|
8224
|
+
let stderrBuffer = "";
|
|
8225
|
+
let settled = false;
|
|
8226
|
+
const timer = setTimeout(() => {
|
|
8227
|
+
if (settled) return;
|
|
8228
|
+
settled = true;
|
|
8229
|
+
cleanup();
|
|
8230
|
+
rejectReady(new Error("timed out waiting for daemon ready line"));
|
|
8231
|
+
}, timeoutMs);
|
|
8232
|
+
const onData = (chunk) => {
|
|
8233
|
+
buffer += chunk.toString();
|
|
8234
|
+
if (!buffer.includes("\n")) return;
|
|
8235
|
+
if (buffer.includes("scorel daemon serving url=") || buffer.includes("scorel host serving url=")) {
|
|
8236
|
+
if (settled) return;
|
|
8237
|
+
settled = true;
|
|
8238
|
+
cleanup();
|
|
8239
|
+
resolveReady();
|
|
8240
|
+
}
|
|
8241
|
+
const newlineIndex = buffer.lastIndexOf("\n");
|
|
8242
|
+
buffer = newlineIndex >= 0 ? buffer.slice(newlineIndex + 1) : buffer;
|
|
8243
|
+
};
|
|
8244
|
+
const onStderr = (chunk) => {
|
|
8245
|
+
stderrBuffer += chunk.toString();
|
|
8246
|
+
};
|
|
8247
|
+
const onExit = (code) => {
|
|
8248
|
+
if (settled) return;
|
|
8249
|
+
settled = true;
|
|
8250
|
+
cleanup();
|
|
8251
|
+
const trimmed = stderrBuffer.trim();
|
|
8252
|
+
const detail = trimmed ? `: ${trimmed}` : "";
|
|
8253
|
+
rejectReady(new Error(`daemon exited before ready code=${code}${detail}`));
|
|
8254
|
+
};
|
|
8255
|
+
const cleanup = () => {
|
|
8256
|
+
clearTimeout(timer);
|
|
8257
|
+
child.stdout?.off("data", onData);
|
|
8258
|
+
child.stderr?.off("data", onStderr);
|
|
8259
|
+
child.off("exit", onExit);
|
|
8260
|
+
};
|
|
8261
|
+
child.stdout.on("data", onData);
|
|
8262
|
+
child.stderr?.on("data", onStderr);
|
|
8263
|
+
child.once("exit", onExit);
|
|
8264
|
+
});
|
|
8265
|
+
detachBackgroundDaemon = (child) => {
|
|
8266
|
+
child.stdout?.destroy();
|
|
8267
|
+
child.stderr?.destroy();
|
|
8268
|
+
child.unref();
|
|
8269
|
+
};
|
|
8270
|
+
nodeEntrypointArgs = (entrypoint) => entrypoint.endsWith(".ts") ? ["--import", "tsx", entrypoint] : [entrypoint];
|
|
7300
8271
|
writeDaemonUsage = (output) => {
|
|
7301
8272
|
output.write(
|
|
7302
8273
|
[
|
|
7303
8274
|
"Usage: scorel host serve [--host <h>] [--port <p>] [--token <t>] [--project <dir>]",
|
|
7304
|
-
" [--relay <relay-url> | --no-relay] [--replace]",
|
|
8275
|
+
" [--relay <relay-url> | --no-relay] [--replace] [--idle-timeout-ms <ms>]",
|
|
8276
|
+
" scorel host start [--host <h>] [--port <p>] [--token <t>] [--project <dir>]",
|
|
8277
|
+
" [--relay <relay-url> | --no-relay] [--replace] [--idle-timeout-ms <ms>]",
|
|
7305
8278
|
" scorel host status [--show-token]",
|
|
7306
8279
|
" scorel host stop",
|
|
7307
8280
|
" scorel host reset",
|
|
@@ -7925,11 +8898,11 @@ var init_relay_server_cli = __esm({
|
|
|
7925
8898
|
});
|
|
7926
8899
|
|
|
7927
8900
|
// apps/cli/src/up-cli.ts
|
|
7928
|
-
import { spawn } from "node:child_process";
|
|
8901
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
7929
8902
|
import { homedir as homedir8 } from "node:os";
|
|
7930
|
-
import { join as join15 } from "node:path";
|
|
7931
|
-
import { fileURLToPath } from "node:url";
|
|
7932
|
-
var DEFAULT_DAEMON_PORT, DEFAULT_WEBUI_PORT, DEFAULT_DAEMON_READY_TIMEOUT_MS, defaultStateDir3, defaultAttachSigint, runCliUp, parseUpFlags, requireValue4,
|
|
8903
|
+
import { dirname as dirname10, join as join15 } from "node:path";
|
|
8904
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
8905
|
+
var DEFAULT_DAEMON_PORT, DEFAULT_WEBUI_PORT, DEFAULT_DAEMON_READY_TIMEOUT_MS, defaultStateDir3, defaultAttachSigint, runCliUp, parseUpFlags, requireValue4, waitForDaemonReady2, pipeWithPrefix, detachBackgroundDaemon2, nodeEntrypointArgs2, pipeStreamLines, once;
|
|
7933
8906
|
var init_up_cli = __esm({
|
|
7934
8907
|
"apps/cli/src/up-cli.ts"() {
|
|
7935
8908
|
"use strict";
|
|
@@ -7952,8 +8925,8 @@ var init_up_cli = __esm({
|
|
|
7952
8925
|
return 1;
|
|
7953
8926
|
}
|
|
7954
8927
|
const stateDir = options.stateDir ?? defaultStateDir3();
|
|
7955
|
-
const cliEntrypoint = options.cliEntrypoint ??
|
|
7956
|
-
const spawnFn = options.spawn ??
|
|
8928
|
+
const cliEntrypoint = options.cliEntrypoint ?? fileURLToPath2(import.meta.url).replace(/up-cli\.ts$/, "index.ts");
|
|
8929
|
+
const spawnFn = options.spawn ?? spawn2;
|
|
7957
8930
|
const readState = options.readState ?? ((dir) => readLocalDaemonState({ stateDir: dir }));
|
|
7958
8931
|
const attachSigint = options.attachSigint ?? defaultAttachSigint;
|
|
7959
8932
|
const readyTimeout = options.daemonReadyTimeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS;
|
|
@@ -7964,9 +8937,7 @@ var init_up_cli = __esm({
|
|
|
7964
8937
|
let daemonState = existingState;
|
|
7965
8938
|
if (!reuseDaemon) {
|
|
7966
8939
|
const daemonArgs = [
|
|
7967
|
-
|
|
7968
|
-
"tsx",
|
|
7969
|
-
cliEntrypoint,
|
|
8940
|
+
...nodeEntrypointArgs2(cliEntrypoint),
|
|
7970
8941
|
"daemon",
|
|
7971
8942
|
"serve",
|
|
7972
8943
|
"--port",
|
|
@@ -7976,19 +8947,19 @@ var init_up_cli = __esm({
|
|
|
7976
8947
|
"--no-relay"
|
|
7977
8948
|
];
|
|
7978
8949
|
daemonChild = spawnFn(process.execPath, daemonArgs, {
|
|
7979
|
-
cwd:
|
|
8950
|
+
cwd: dirname10(cliEntrypoint),
|
|
7980
8951
|
env: { ...process.env },
|
|
8952
|
+
detached: true,
|
|
7981
8953
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7982
8954
|
});
|
|
7983
8955
|
try {
|
|
7984
|
-
await
|
|
8956
|
+
await waitForDaemonReady2(daemonChild, readyTimeout);
|
|
7985
8957
|
} catch (cause) {
|
|
7986
8958
|
options.error.write(`scorel up error: ${cause.message}
|
|
7987
8959
|
`);
|
|
7988
8960
|
daemonChild.kill("SIGTERM");
|
|
7989
8961
|
return 1;
|
|
7990
8962
|
}
|
|
7991
|
-
pipeWithPrefix(daemonChild, "[daemon]", options.output, options.error);
|
|
7992
8963
|
daemonState = await readState(stateDir);
|
|
7993
8964
|
}
|
|
7994
8965
|
if (!daemonState) {
|
|
@@ -7996,16 +8967,17 @@ var init_up_cli = __esm({
|
|
|
7996
8967
|
daemonChild?.kill("SIGTERM");
|
|
7997
8968
|
return 1;
|
|
7998
8969
|
}
|
|
8970
|
+
if (daemonChild) {
|
|
8971
|
+
detachBackgroundDaemon2(daemonChild);
|
|
8972
|
+
}
|
|
7999
8973
|
const webuiArgs = [
|
|
8000
|
-
|
|
8001
|
-
"tsx",
|
|
8002
|
-
cliEntrypoint,
|
|
8974
|
+
...nodeEntrypointArgs2(cliEntrypoint),
|
|
8003
8975
|
"webui",
|
|
8004
8976
|
"--port",
|
|
8005
8977
|
String(flags.webuiPort)
|
|
8006
8978
|
];
|
|
8007
8979
|
const webuiChild = spawnFn(process.execPath, webuiArgs, {
|
|
8008
|
-
cwd:
|
|
8980
|
+
cwd: dirname10(cliEntrypoint),
|
|
8009
8981
|
env: { ...process.env },
|
|
8010
8982
|
stdio: ["ignore", "pipe", "pipe"]
|
|
8011
8983
|
});
|
|
@@ -8022,33 +8994,21 @@ var init_up_cli = __esm({
|
|
|
8022
8994
|
return;
|
|
8023
8995
|
}
|
|
8024
8996
|
shuttingDown = true;
|
|
8025
|
-
daemonChild?.kill("SIGTERM");
|
|
8026
8997
|
webuiChild.kill("SIGTERM");
|
|
8027
8998
|
});
|
|
8028
|
-
const daemonExit = daemonChild ? once(daemonChild) : Promise.resolve(0);
|
|
8029
8999
|
const webuiExit = once(webuiChild);
|
|
8030
|
-
const daemonDeathWatcher = daemonChild ? daemonExit.then((code) => {
|
|
8031
|
-
if (!shuttingDown) {
|
|
8032
|
-
shuttingDown = true;
|
|
8033
|
-
options.error.write(`scorel up daemon exited code=${code}
|
|
8034
|
-
`);
|
|
8035
|
-
webuiChild.kill("SIGTERM");
|
|
8036
|
-
}
|
|
8037
|
-
return code;
|
|
8038
|
-
}) : Promise.resolve(0);
|
|
8039
9000
|
const webuiDeathWatcher = webuiExit.then((code) => {
|
|
8040
9001
|
if (!shuttingDown) {
|
|
8041
9002
|
shuttingDown = true;
|
|
8042
9003
|
options.error.write(`scorel up webui exited code=${code}
|
|
8043
9004
|
`);
|
|
8044
|
-
daemonChild?.kill("SIGTERM");
|
|
8045
9005
|
}
|
|
8046
9006
|
return code;
|
|
8047
9007
|
});
|
|
8048
|
-
const
|
|
9008
|
+
const webuiCode = await webuiDeathWatcher;
|
|
8049
9009
|
detachSigint();
|
|
8050
9010
|
options.output.write("scorel up stopped\n");
|
|
8051
|
-
return
|
|
9011
|
+
return webuiCode === 0 ? 0 : 1;
|
|
8052
9012
|
};
|
|
8053
9013
|
parseUpFlags = (argv, defaultCwd) => {
|
|
8054
9014
|
let daemonPort = DEFAULT_DAEMON_PORT;
|
|
@@ -8088,7 +9048,7 @@ var init_up_cli = __esm({
|
|
|
8088
9048
|
}
|
|
8089
9049
|
return value;
|
|
8090
9050
|
};
|
|
8091
|
-
|
|
9051
|
+
waitForDaemonReady2 = (child, timeoutMs) => new Promise((resolveReady, rejectReady) => {
|
|
8092
9052
|
if (!child.stdout) {
|
|
8093
9053
|
rejectReady(new Error("daemon child has no stdout stream"));
|
|
8094
9054
|
return;
|
|
@@ -8145,6 +9105,12 @@ var init_up_cli = __esm({
|
|
|
8145
9105
|
pipeStreamLines(child.stderr, prefix, error);
|
|
8146
9106
|
}
|
|
8147
9107
|
};
|
|
9108
|
+
detachBackgroundDaemon2 = (child) => {
|
|
9109
|
+
child.stdout?.destroy();
|
|
9110
|
+
child.stderr?.destroy();
|
|
9111
|
+
child.unref();
|
|
9112
|
+
};
|
|
9113
|
+
nodeEntrypointArgs2 = (entrypoint) => entrypoint.endsWith(".ts") ? ["--import", "tsx", entrypoint] : [entrypoint];
|
|
8148
9114
|
pipeStreamLines = (stream, prefix, destination) => {
|
|
8149
9115
|
let buffer = "";
|
|
8150
9116
|
stream.setEncoding?.("utf8");
|
|
@@ -8174,10 +9140,10 @@ var init_up_cli = __esm({
|
|
|
8174
9140
|
});
|
|
8175
9141
|
|
|
8176
9142
|
// apps/cli/src/webui-cli.ts
|
|
8177
|
-
import { spawn as
|
|
9143
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
8178
9144
|
import { existsSync as existsSync4 } from "node:fs";
|
|
8179
|
-
import { dirname as
|
|
8180
|
-
import { fileURLToPath as
|
|
9145
|
+
import { dirname as dirname11, resolve as resolve6 } from "node:path";
|
|
9146
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
8181
9147
|
var DEFAULT_PORT3, DEFAULT_HOST3, runCliWebUi, findWebuiAppDir, buildWebUiSpawnPlan, parseWebUiFlags, requireValue5, waitForChildExit;
|
|
8182
9148
|
var init_webui_cli = __esm({
|
|
8183
9149
|
"apps/cli/src/webui-cli.ts"() {
|
|
@@ -8199,7 +9165,7 @@ var init_webui_cli = __esm({
|
|
|
8199
9165
|
return 1;
|
|
8200
9166
|
}
|
|
8201
9167
|
const plan = buildWebUiSpawnPlan(flags, webuiAppDir);
|
|
8202
|
-
const spawnFn = options.spawn ??
|
|
9168
|
+
const spawnFn = options.spawn ?? spawn3;
|
|
8203
9169
|
const child = spawnFn(plan.command, plan.argv, {
|
|
8204
9170
|
cwd: plan.cwd,
|
|
8205
9171
|
env: plan.env,
|
|
@@ -8208,7 +9174,7 @@ var init_webui_cli = __esm({
|
|
|
8208
9174
|
return await waitForChildExit(child, options);
|
|
8209
9175
|
};
|
|
8210
9176
|
findWebuiAppDir = () => {
|
|
8211
|
-
let cursor =
|
|
9177
|
+
let cursor = dirname11(fileURLToPath3(import.meta.url));
|
|
8212
9178
|
for (let depth = 0; depth < 8; depth += 1) {
|
|
8213
9179
|
const candidate = resolve6(cursor, "apps/webui/package.json");
|
|
8214
9180
|
if (existsSync4(candidate)) {
|
|
@@ -8300,8 +9266,8 @@ import { createHash as createHash3 } from "node:crypto";
|
|
|
8300
9266
|
import { appendFile as appendFile4, mkdir as mkdir8, readFile as readFile13, realpath as realpath3, readdir as readdir7, writeFile as writeFile8 } from "node:fs/promises";
|
|
8301
9267
|
import { createInterface } from "node:readline/promises";
|
|
8302
9268
|
import { homedir as homedir9 } from "node:os";
|
|
8303
|
-
import { fileURLToPath as
|
|
8304
|
-
import { basename as
|
|
9269
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
9270
|
+
import { basename as basename4, dirname as dirname12, join as join16 } from "node:path";
|
|
8305
9271
|
var cliAppName, cliClientDependency, cliDaemonDependency, defaultSessionsDir, defaultStateDir4, runCli, runProject, runLogs, runAttach, attachCacheScope, attachCacheFilePath, attachDiagnosticsFilePath, findAttachDiagnosticsFilePath, stateDirFromSessionsDir, AttachDiagnostics, readAttachCache, writeAttachCache, emptyAttachCacheSnapshot, mergePersistentEvents, highestSeq, highestCachedStreamSeq, updateAttachCacheSnapshot, removeCompletedTransients, isCachedTransientMessage, AsyncInputQueue, parseAttachOptions, parseLogsOptions, runChat, createSigintHandler, loadOrCreateSession, parseChatOptions, requireValue6, promptIfInteractive, writeUsage, writeProjectUsage, writeEventError, writeToolResult, redactDiagnosticFields, formatDiagnosticLine2, formatDiagnosticValue2, AttachEventRenderer, blocksToText, isCliEntrypoint;
|
|
8306
9272
|
var init_index = __esm({
|
|
8307
9273
|
async "apps/cli/src/index.ts"() {
|
|
@@ -8634,7 +9600,7 @@ var init_index = __esm({
|
|
|
8634
9600
|
if (!sessionsDir) {
|
|
8635
9601
|
return defaultStateDir4();
|
|
8636
9602
|
}
|
|
8637
|
-
return
|
|
9603
|
+
return basename4(sessionsDir) === "sessions" ? dirname12(sessionsDir) : sessionsDir;
|
|
8638
9604
|
};
|
|
8639
9605
|
AttachDiagnostics = class {
|
|
8640
9606
|
#stateDir;
|
|
@@ -8686,7 +9652,7 @@ var init_index = __esm({
|
|
|
8686
9652
|
}
|
|
8687
9653
|
const filePath = attachDiagnosticsFilePath(this.#stateDir, this.#scope, this.#sessionId);
|
|
8688
9654
|
this.#writes.push(
|
|
8689
|
-
mkdir8(
|
|
9655
|
+
mkdir8(dirname12(filePath), { recursive: true }).then(() => appendFile4(filePath, `${line}
|
|
8690
9656
|
`, "utf8"))
|
|
8691
9657
|
);
|
|
8692
9658
|
}
|
|
@@ -8716,7 +9682,7 @@ var init_index = __esm({
|
|
|
8716
9682
|
const filePath = attachCacheFilePath(stateDir, scope, sessionId);
|
|
8717
9683
|
const uniqueEvents = mergePersistentEvents(snapshot.events);
|
|
8718
9684
|
const transients = removeCompletedTransients(snapshot.transients, uniqueEvents);
|
|
8719
|
-
await mkdir8(
|
|
9685
|
+
await mkdir8(dirname12(filePath), { recursive: true });
|
|
8720
9686
|
await writeFile8(
|
|
8721
9687
|
filePath,
|
|
8722
9688
|
`${JSON.stringify({ version: 1, scope, sessionId: String(sessionId), events: uniqueEvents, transients }, null, 2)}
|
|
@@ -8853,12 +9819,14 @@ var init_index = __esm({
|
|
|
8853
9819
|
return { sessionId, tail, attach, remoteUrl };
|
|
8854
9820
|
};
|
|
8855
9821
|
runChat = async (options, io) => {
|
|
8856
|
-
const
|
|
8857
|
-
const
|
|
9822
|
+
const configScope = { scorelHomeDir: options.stateDir };
|
|
9823
|
+
const loadProjectConfig = async (project2) => options.config ?? await loadScorelConfig({ cwd: project2.workDir, ...configScope });
|
|
9824
|
+
const loadProjectConfigProfile = async (project2) => options.config ?? await loadScorelConfigProfile({ cwd: project2.workDir, ...configScope });
|
|
8858
9825
|
const daemon = new ScorelHost({
|
|
8859
9826
|
sessionsDir: options.sessionsDir,
|
|
8860
9827
|
projectsPath: join16(options.stateDir, "projects.json"),
|
|
8861
9828
|
deviceId: asDeviceId("device_local"),
|
|
9829
|
+
scorelHomeDir: options.stateDir,
|
|
8862
9830
|
loadConfig: async ({ project: project2 }) => loadProjectConfig(project2),
|
|
8863
9831
|
loadConfigProfile: async ({ project: project2 }) => loadProjectConfigProfile(project2),
|
|
8864
9832
|
createRuntime: async ({ project: project2, selectedModel, purpose }) => createRealRuntime({
|
|
@@ -8992,8 +9960,10 @@ var init_index = __esm({
|
|
|
8992
9960
|
"Usage: scorel chat [--session <id>] [--cwd <dir>]",
|
|
8993
9961
|
" scorel [--session <id>] [--cwd <dir>]",
|
|
8994
9962
|
" scorel attach --session <id> --remote <ws-url> --token <token>",
|
|
9963
|
+
" scorel host start [--host <h>] [--port <p>] [--token <t>] [--project <dir>]",
|
|
9964
|
+
" [--relay <relay-url> | --no-relay] [--replace] [--idle-timeout-ms <ms>]",
|
|
8995
9965
|
" scorel host serve [--host <h>] [--port <p>] [--token <t>] [--project <dir>]",
|
|
8996
|
-
" [--relay <relay-url> | --no-relay] [--replace]",
|
|
9966
|
+
" [--relay <relay-url> | --no-relay] [--replace] [--idle-timeout-ms <ms>]",
|
|
8997
9967
|
" scorel host status [--show-token]",
|
|
8998
9968
|
" scorel host stop",
|
|
8999
9969
|
" scorel host reset",
|
|
@@ -9132,7 +10102,7 @@ ${text}
|
|
|
9132
10102
|
if (!process.argv[1]) return false;
|
|
9133
10103
|
const [argvPath, modulePath] = await Promise.all([
|
|
9134
10104
|
realpath3(process.argv[1]).catch(() => process.argv[1]),
|
|
9135
|
-
realpath3(
|
|
10105
|
+
realpath3(fileURLToPath4(import.meta.url)).catch(() => fileURLToPath4(import.meta.url))
|
|
9136
10106
|
]);
|
|
9137
10107
|
return argvPath === modulePath;
|
|
9138
10108
|
};
|