@threadbase-sh/streamer 1.52.2 → 1.52.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 +8 -4
- package/dist/cli.cjs +102 -32
- package/dist/cli.cjs.map +1 -1
- package/dist/index.cjs +62 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -2
- package/dist/index.d.ts +52 -2
- package/dist/index.js +62 -25
- 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() {
|
|
@@ -14480,6 +14495,7 @@ var StreamerServer = class {
|
|
|
14480
14495
|
dbPool = null;
|
|
14481
14496
|
dbInstanceId = null;
|
|
14482
14497
|
disableDb = false;
|
|
14498
|
+
host;
|
|
14483
14499
|
// Skip the startup warm-up scan (test hook; see ServerConfig.skipStartupWarmup).
|
|
14484
14500
|
skipStartupWarmup;
|
|
14485
14501
|
autoResumeOnBoot;
|
|
@@ -14495,6 +14511,10 @@ var StreamerServer = class {
|
|
|
14495
14511
|
// Resolved once at boot; see src/feature-flags.ts. Total map — every registry
|
|
14496
14512
|
// id is present, so indexing it never yields undefined.
|
|
14497
14513
|
featureFlags;
|
|
14514
|
+
// Which rung of the precedence chain decided each flag. Reported at boot and
|
|
14515
|
+
// over GET /api/config/feature-flags — the resolved boolean alone cannot say
|
|
14516
|
+
// whether a value came from the environment, the CLI, server.yaml or nowhere.
|
|
14517
|
+
featureFlagSources;
|
|
14498
14518
|
// Derived from featureFlags.codexSystemPrompt. Kept as its own field so the
|
|
14499
14519
|
// read site in startFresh() is unchanged.
|
|
14500
14520
|
codexSystemPromptEnabled;
|
|
@@ -14601,16 +14621,20 @@ var StreamerServer = class {
|
|
|
14601
14621
|
}
|
|
14602
14622
|
this.verbose = config.verbose ?? false;
|
|
14603
14623
|
this.disableDb = config.disableDb ?? false;
|
|
14624
|
+
this.host = config.host;
|
|
14604
14625
|
this.skipStartupWarmup = config.skipStartupWarmup ?? false;
|
|
14605
14626
|
this.autoResumeOnBoot = config.autoResumeOnBoot ?? false;
|
|
14606
14627
|
this.scanProfiles = config.scanProfiles;
|
|
14607
14628
|
this.codexRoots = config.codexRoots ?? [(0, import_path22.join)((0, import_os12.homedir)(), ".codex", "sessions")];
|
|
14608
14629
|
this.ptyGracePeriodMs = config.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
|
|
14609
14630
|
this.defaultSystemPrompt = config.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
14610
|
-
|
|
14611
|
-
|
|
14612
|
-
|
|
14613
|
-
|
|
14631
|
+
const flagResolution = resolveFeatureFlags({
|
|
14632
|
+
override: config.codexSystemPromptEnabled === void 0 ? void 0 : { codexSystemPrompt: config.codexSystemPromptEnabled },
|
|
14633
|
+
cli: config.featureFlags,
|
|
14634
|
+
yaml: loadFeatureFlags()
|
|
14635
|
+
});
|
|
14636
|
+
this.featureFlags = flagResolution.values;
|
|
14637
|
+
this.featureFlagSources = flagResolution.sources;
|
|
14614
14638
|
this.codexSystemPromptEnabled = this.featureFlags.codexSystemPrompt;
|
|
14615
14639
|
this.defaultPermissionMode = config.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
|
|
14616
14640
|
this.defaultModel = config.defaultModel ?? "sonnet";
|
|
@@ -14655,13 +14679,12 @@ var StreamerServer = class {
|
|
|
14655
14679
|
});
|
|
14656
14680
|
this.includeAgents = parseIncludeAgentsEnv(process.env.THREADBASE_INCLUDE_AGENTS);
|
|
14657
14681
|
this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
|
|
14658
|
-
|
|
14659
|
-
|
|
14660
|
-
|
|
14661
|
-
|
|
14662
|
-
|
|
14663
|
-
|
|
14664
|
-
}
|
|
14682
|
+
this.log.info(`Feature flags: ${describeFeatureFlags(flagResolution)}`, {
|
|
14683
|
+
event: "config.feature_flags",
|
|
14684
|
+
values: this.featureFlags,
|
|
14685
|
+
sources: this.featureFlagSources,
|
|
14686
|
+
nonDefault: nonDefaultFeatureFlags(this.featureFlags)
|
|
14687
|
+
});
|
|
14665
14688
|
const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config.browseRoot;
|
|
14666
14689
|
if (rawRoot) {
|
|
14667
14690
|
(0, import_promises7.realpath)(rawRoot).then((resolved) => {
|
|
@@ -15253,7 +15276,7 @@ var StreamerServer = class {
|
|
|
15253
15276
|
await runMigrations(this.dbPool);
|
|
15254
15277
|
this.log.info("Database migrations applied", { event: "db.migrations_applied" });
|
|
15255
15278
|
}
|
|
15256
|
-
await this.bindWithRetry(port);
|
|
15279
|
+
await this.bindWithRetry(port, this.host);
|
|
15257
15280
|
if (!this.ptyManager.isRemote()) {
|
|
15258
15281
|
this.idleReaperTimer = setInterval(() => this.reapIdleSessions(), IDLE_REAP_SWEEP_MS);
|
|
15259
15282
|
this.idleReaperTimer.unref?.();
|
|
@@ -15262,7 +15285,8 @@ var StreamerServer = class {
|
|
|
15262
15285
|
{
|
|
15263
15286
|
this.log.info(`Streamer server listening on port ${port}`, {
|
|
15264
15287
|
port,
|
|
15265
|
-
event: "server.listening"
|
|
15288
|
+
event: "server.listening",
|
|
15289
|
+
...this.host !== void 0 && { host: this.host }
|
|
15266
15290
|
});
|
|
15267
15291
|
try {
|
|
15268
15292
|
this.runtimeStore = RuntimeStore.open(this.runtimeDbPath);
|
|
@@ -15476,15 +15500,15 @@ var StreamerServer = class {
|
|
|
15476
15500
|
// Bind the HTTP listener, retrying on a transient EADDRINUSE. See the call
|
|
15477
15501
|
// site in listen() for why the race exists (kickstart -k relaunch). Total
|
|
15478
15502
|
// worst case ≈ 6 × 500 ms = 3 s before the final attempt rethrows.
|
|
15479
|
-
async bindWithRetry(port, attempts = 6, delayMs = 500) {
|
|
15503
|
+
async bindWithRetry(port, host, attempts = 6, delayMs = 500) {
|
|
15480
15504
|
this.binding = true;
|
|
15481
15505
|
try {
|
|
15482
|
-
await this.bindWithRetryLoop(port, attempts, delayMs);
|
|
15506
|
+
await this.bindWithRetryLoop(port, host, attempts, delayMs);
|
|
15483
15507
|
} finally {
|
|
15484
15508
|
this.binding = false;
|
|
15485
15509
|
}
|
|
15486
15510
|
}
|
|
15487
|
-
async bindWithRetryLoop(port, attempts, delayMs) {
|
|
15511
|
+
async bindWithRetryLoop(port, host, attempts, delayMs) {
|
|
15488
15512
|
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
15489
15513
|
try {
|
|
15490
15514
|
await new Promise((resolve2, reject) => {
|
|
@@ -15498,7 +15522,11 @@ var StreamerServer = class {
|
|
|
15498
15522
|
};
|
|
15499
15523
|
this.httpServer.once("error", onError);
|
|
15500
15524
|
this.httpServer.once("listening", onListening);
|
|
15501
|
-
|
|
15525
|
+
if (host === void 0) {
|
|
15526
|
+
this.httpServer.listen(port);
|
|
15527
|
+
} else {
|
|
15528
|
+
this.httpServer.listen(port, host);
|
|
15529
|
+
}
|
|
15502
15530
|
});
|
|
15503
15531
|
return;
|
|
15504
15532
|
} catch (err) {
|
|
@@ -15506,13 +15534,18 @@ var StreamerServer = class {
|
|
|
15506
15534
|
if (e.code === "EADDRINUSE" && attempt === attempts) {
|
|
15507
15535
|
this.log.error(
|
|
15508
15536
|
`port ${port} still busy (EADDRINUSE) after ${attempts} attempts; giving up`,
|
|
15509
|
-
{
|
|
15537
|
+
{
|
|
15538
|
+
port,
|
|
15539
|
+
attempts,
|
|
15540
|
+
event: "server.bind_failed",
|
|
15541
|
+
...host !== void 0 && { host }
|
|
15542
|
+
}
|
|
15510
15543
|
);
|
|
15511
15544
|
}
|
|
15512
15545
|
if (e.code !== "EADDRINUSE" || attempt === attempts) throw err;
|
|
15513
15546
|
this.log.debug?.(
|
|
15514
15547
|
`port ${port} busy (EADDRINUSE), retry ${attempt}/${attempts - 1} in ${delayMs}ms`,
|
|
15515
|
-
{ port, attempt, event: "server.bind_retry" }
|
|
15548
|
+
{ port, attempt, event: "server.bind_retry", ...host !== void 0 && { host } }
|
|
15516
15549
|
);
|
|
15517
15550
|
await new Promise((r) => setTimeout(r, delayMs));
|
|
15518
15551
|
}
|
|
@@ -15674,7 +15707,11 @@ var StreamerServer = class {
|
|
|
15674
15707
|
* the absence of that field is the signal that this endpoint is read-only.
|
|
15675
15708
|
*/
|
|
15676
15709
|
getFeatureFlagsConfig() {
|
|
15677
|
-
return {
|
|
15710
|
+
return {
|
|
15711
|
+
registry: FEATURE_FLAGS,
|
|
15712
|
+
values: this.featureFlags,
|
|
15713
|
+
sources: this.featureFlagSources
|
|
15714
|
+
};
|
|
15678
15715
|
}
|
|
15679
15716
|
getClaudeFlagsConfig() {
|
|
15680
15717
|
return {
|