@threadbase-sh/streamer 1.52.3 → 1.52.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +119 -29
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +81 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +81 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -537,11 +537,12 @@ function validateFeatureFlagValues(raw) {
|
|
|
537
537
|
const out = {};
|
|
538
538
|
const dropped = [];
|
|
539
539
|
for (const [id, value] of Object.entries(raw)) {
|
|
540
|
-
|
|
540
|
+
const def = findFeatureFlag(id);
|
|
541
|
+
if (!def || typeof value !== "boolean") {
|
|
541
542
|
dropped.push(id);
|
|
542
543
|
continue;
|
|
543
544
|
}
|
|
544
|
-
out[id] = value;
|
|
545
|
+
out[def.id] = value;
|
|
545
546
|
}
|
|
546
547
|
if (dropped.length > 0) {
|
|
547
548
|
getLogger("feature-flags").warn(
|
|
@@ -556,15 +557,29 @@ function validateFeatureFlagValues(raw) {
|
|
|
556
557
|
}
|
|
557
558
|
function resolveFeatureFlags(opts) {
|
|
558
559
|
const env = opts?.env ?? process.env;
|
|
559
|
-
const
|
|
560
|
+
const values = {};
|
|
561
|
+
const sources = {};
|
|
560
562
|
for (const def of FEATURE_FLAGS) {
|
|
561
|
-
|
|
563
|
+
const rungs = [
|
|
564
|
+
["override", opts?.override?.[def.id]],
|
|
565
|
+
["env", parseBooleanEnv(env[def.env])],
|
|
566
|
+
["cli", opts?.cli?.[def.id]],
|
|
567
|
+
["yaml", opts?.yaml?.[def.id]]
|
|
568
|
+
];
|
|
569
|
+
const won = rungs.find(([, v]) => v !== void 0);
|
|
570
|
+
values[def.id] = won ? won[1] : def.default;
|
|
571
|
+
sources[def.id] = won ? won[0] : "default";
|
|
562
572
|
}
|
|
563
|
-
return
|
|
573
|
+
return { values, sources };
|
|
564
574
|
}
|
|
565
575
|
function nonDefaultFeatureFlags(values) {
|
|
566
576
|
return FEATURE_FLAGS.filter((f) => values[f.id] !== f.default).map((f) => f.id);
|
|
567
577
|
}
|
|
578
|
+
function describeFeatureFlags(resolution) {
|
|
579
|
+
return FEATURE_FLAGS.map(
|
|
580
|
+
(f) => `${f.id}=${resolution.values[f.id]}(${resolution.sources[f.id]})`
|
|
581
|
+
).join(" ");
|
|
582
|
+
}
|
|
568
583
|
|
|
569
584
|
// src/auth.ts
|
|
570
585
|
function configDir() {
|
|
@@ -13267,6 +13282,7 @@ function autoResumeSkipReason(row, opts) {
|
|
|
13267
13282
|
if (opts.now - row.status_updated_at > AUTO_RESUME_WINDOW_MS) return "too_old";
|
|
13268
13283
|
if (!opts.projectExists(row.project_path)) return "project_missing";
|
|
13269
13284
|
if (resumeIdForRow(row) == null) return "resume_identity_missing";
|
|
13285
|
+
if (!opts.historyExists(row)) return "history_missing";
|
|
13270
13286
|
return null;
|
|
13271
13287
|
}
|
|
13272
13288
|
function planAutoResume(rows, opts) {
|
|
@@ -13528,7 +13544,34 @@ var SessionRegistryBoot = class {
|
|
|
13528
13544
|
/** Resume only the recent sessions the user explicitly allowed us to start at boot. */
|
|
13529
13545
|
async autoResumePreviousSessions(rows) {
|
|
13530
13546
|
if (!this.autoResumeOnBoot) return;
|
|
13531
|
-
const
|
|
13547
|
+
const now = Date.now();
|
|
13548
|
+
const baseOptions = { now, projectExists: import_fs25.existsSync, historyExists: () => true };
|
|
13549
|
+
const historyExists = /* @__PURE__ */ new Map();
|
|
13550
|
+
const preflights = /* @__PURE__ */ new Set();
|
|
13551
|
+
for (const row of rows) {
|
|
13552
|
+
if (autoResumeSkipReason(row, baseOptions) != null) {
|
|
13553
|
+
historyExists.set(row.session_id, false);
|
|
13554
|
+
continue;
|
|
13555
|
+
}
|
|
13556
|
+
while (preflights.size >= AUTO_RESUME_CONCURRENCY) {
|
|
13557
|
+
await Promise.race(preflights);
|
|
13558
|
+
}
|
|
13559
|
+
const preflight = (async () => {
|
|
13560
|
+
try {
|
|
13561
|
+
const target = await this.deps.resolveConversationTarget(row.session_id);
|
|
13562
|
+
historyExists.set(row.session_id, target.ok || target.reason !== "history_file_missing");
|
|
13563
|
+
} catch {
|
|
13564
|
+
historyExists.set(row.session_id, true);
|
|
13565
|
+
}
|
|
13566
|
+
})();
|
|
13567
|
+
preflights.add(preflight);
|
|
13568
|
+
void preflight.then(() => preflights.delete(preflight));
|
|
13569
|
+
}
|
|
13570
|
+
await Promise.all(preflights);
|
|
13571
|
+
const plan = planAutoResume(rows, {
|
|
13572
|
+
...baseOptions,
|
|
13573
|
+
historyExists: (row) => historyExists.get(row.session_id) ?? false
|
|
13574
|
+
});
|
|
13532
13575
|
const skippedBy = {};
|
|
13533
13576
|
for (const { row, reason } of plan.skipped) {
|
|
13534
13577
|
skippedBy[reason] = (skippedBy[reason] ?? 0) + 1;
|
|
@@ -14496,6 +14539,10 @@ var StreamerServer = class {
|
|
|
14496
14539
|
// Resolved once at boot; see src/feature-flags.ts. Total map — every registry
|
|
14497
14540
|
// id is present, so indexing it never yields undefined.
|
|
14498
14541
|
featureFlags;
|
|
14542
|
+
// Which rung of the precedence chain decided each flag. Reported at boot and
|
|
14543
|
+
// over GET /api/config/feature-flags — the resolved boolean alone cannot say
|
|
14544
|
+
// whether a value came from the environment, the CLI, server.yaml or nowhere.
|
|
14545
|
+
featureFlagSources;
|
|
14499
14546
|
// Derived from featureFlags.codexSystemPrompt. Kept as its own field so the
|
|
14500
14547
|
// read site in startFresh() is unchanged.
|
|
14501
14548
|
codexSystemPromptEnabled;
|
|
@@ -14609,10 +14656,13 @@ var StreamerServer = class {
|
|
|
14609
14656
|
this.codexRoots = config.codexRoots ?? [(0, import_path22.join)((0, import_os12.homedir)(), ".codex", "sessions")];
|
|
14610
14657
|
this.ptyGracePeriodMs = config.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
|
|
14611
14658
|
this.defaultSystemPrompt = config.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
14612
|
-
|
|
14613
|
-
|
|
14614
|
-
|
|
14615
|
-
|
|
14659
|
+
const flagResolution = resolveFeatureFlags({
|
|
14660
|
+
override: config.codexSystemPromptEnabled === void 0 ? void 0 : { codexSystemPrompt: config.codexSystemPromptEnabled },
|
|
14661
|
+
cli: config.featureFlags,
|
|
14662
|
+
yaml: loadFeatureFlags()
|
|
14663
|
+
});
|
|
14664
|
+
this.featureFlags = flagResolution.values;
|
|
14665
|
+
this.featureFlagSources = flagResolution.sources;
|
|
14616
14666
|
this.codexSystemPromptEnabled = this.featureFlags.codexSystemPrompt;
|
|
14617
14667
|
this.defaultPermissionMode = config.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
|
|
14618
14668
|
this.defaultModel = config.defaultModel ?? "sonnet";
|
|
@@ -14653,17 +14703,17 @@ var StreamerServer = class {
|
|
|
14653
14703
|
selfPtyEndedAt: this.selfPtyEndedAt,
|
|
14654
14704
|
resumeSession: (opts) => this.sessionHandlers.resumeSession(opts),
|
|
14655
14705
|
watchConversationFile: (sessionId, historyId) => this.sessionWatchers.watchConversationFile(sessionId, historyId),
|
|
14656
|
-
broadcastSessionList: () => this.wsHub.broadcast(this.sessionListPayload())
|
|
14706
|
+
broadcastSessionList: () => this.wsHub.broadcast(this.sessionListPayload()),
|
|
14707
|
+
resolveConversationTarget: (sessionId) => this.resolveConversationTarget(sessionId)
|
|
14657
14708
|
});
|
|
14658
14709
|
this.includeAgents = parseIncludeAgentsEnv(process.env.THREADBASE_INCLUDE_AGENTS);
|
|
14659
14710
|
this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
|
|
14665
|
-
|
|
14666
|
-
}
|
|
14711
|
+
this.log.info(`Feature flags: ${describeFeatureFlags(flagResolution)}`, {
|
|
14712
|
+
event: "config.feature_flags",
|
|
14713
|
+
values: this.featureFlags,
|
|
14714
|
+
sources: this.featureFlagSources,
|
|
14715
|
+
nonDefault: nonDefaultFeatureFlags(this.featureFlags)
|
|
14716
|
+
});
|
|
14667
14717
|
const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config.browseRoot;
|
|
14668
14718
|
if (rawRoot) {
|
|
14669
14719
|
(0, import_promises7.realpath)(rawRoot).then((resolved) => {
|
|
@@ -15686,7 +15736,11 @@ var StreamerServer = class {
|
|
|
15686
15736
|
* the absence of that field is the signal that this endpoint is read-only.
|
|
15687
15737
|
*/
|
|
15688
15738
|
getFeatureFlagsConfig() {
|
|
15689
|
-
return {
|
|
15739
|
+
return {
|
|
15740
|
+
registry: FEATURE_FLAGS,
|
|
15741
|
+
values: this.featureFlags,
|
|
15742
|
+
sources: this.featureFlagSources
|
|
15743
|
+
};
|
|
15690
15744
|
}
|
|
15691
15745
|
getClaudeFlagsConfig() {
|
|
15692
15746
|
return {
|
|
@@ -15859,13 +15913,17 @@ var StreamerServer = class {
|
|
|
15859
15913
|
conv = await this.conversationHandlers.findConversationByUuid(boundId);
|
|
15860
15914
|
}
|
|
15861
15915
|
}
|
|
15916
|
+
const cachedConvMeta = this.cache?.getMetaById(historyId);
|
|
15917
|
+
const cachedPath = cachedConvMeta?.filePath ? toNativeFilePath(cachedConvMeta.filePath) : null;
|
|
15918
|
+
const cachedCodexPath = (registryProvider === CODEX_CLI_PROVIDER || cachedConvMeta?.provider === CODEX_CLI_PROVIDER) && cachedPath != null && (0, import_fs27.existsSync)(cachedPath) ? cachedPath : null;
|
|
15862
15919
|
const jsonlCwd = jsonlPath ? await this.conversationHandlers.readCwdFromJsonl(jsonlPath) : null;
|
|
15863
|
-
const projectPath = jsonlCwd ?? conv?.projectPath;
|
|
15920
|
+
const projectPath = jsonlCwd ?? conv?.projectPath ?? (cachedCodexPath ? cachedConvMeta?.projectPath : null);
|
|
15864
15921
|
if (!projectPath) {
|
|
15865
|
-
if (!conv && !jsonlPath)
|
|
15922
|
+
if (!conv && !jsonlPath && !cachedCodexPath) {
|
|
15923
|
+
return { ok: false, reason: "history_file_missing" };
|
|
15924
|
+
}
|
|
15866
15925
|
return { ok: false, reason: "no_project_path" };
|
|
15867
15926
|
}
|
|
15868
|
-
const cachedConvMeta = this.cache?.getMetaById(historyId);
|
|
15869
15927
|
const provider = coerceProviderForRunner(
|
|
15870
15928
|
conv?.provider ?? cachedConvMeta?.provider ?? registryProvider
|
|
15871
15929
|
);
|
|
@@ -15879,7 +15937,7 @@ var StreamerServer = class {
|
|
|
15879
15937
|
// conversation. Kept separate from `jsonlPath` deliberately: feeding it to
|
|
15880
15938
|
// conversationBusy() would newly arm the mtime heuristic for Codex, which
|
|
15881
15939
|
// is exactly the over-broad signal the report ruled out.
|
|
15882
|
-
historyPath: jsonlPath ?? conv?.filePath ?? null,
|
|
15940
|
+
historyPath: jsonlPath ?? conv?.filePath ?? cachedCodexPath ?? null,
|
|
15883
15941
|
conv,
|
|
15884
15942
|
projectPath,
|
|
15885
15943
|
provider
|