@datename/fastcode-termux 0.1.6-beta → 0.1.8-beta.0
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/LICENSE +4 -0
- package/README.md +50 -17
- package/dist/agent/approval-json.d.ts +43 -0
- package/dist/agent/approval-json.js +69 -0
- package/dist/agent/approval-native.d.ts +3 -0
- package/dist/agent/approval-native.js +165 -0
- package/dist/agent/approval-store.d.ts +16 -0
- package/dist/agent/approval-store.js +21 -0
- package/dist/agent/approval.d.ts +33 -0
- package/dist/agent/approval.js +40 -5
- package/dist/agent/compaction.d.ts +2 -0
- package/dist/agent/compaction.js +60 -17
- package/dist/agent/guards.d.ts +16 -16
- package/dist/agent/guards.js +978 -24
- package/dist/agent/policy/defaults.d.ts +16 -0
- package/dist/agent/policy/defaults.js +17 -0
- package/dist/agent/policy/egress.d.ts +32 -0
- package/dist/agent/policy/egress.js +280 -0
- package/dist/agent/process-tree.d.ts +20 -0
- package/dist/agent/process-tree.js +81 -10
- package/dist/agent/protocol.d.ts +20 -1
- package/dist/agent/protocol.js +165 -38
- package/dist/agent/registry.d.ts +3 -1
- package/dist/agent/registry.js +168 -11
- package/dist/agent/runner.d.ts +21 -0
- package/dist/agent/runner.js +44 -5
- package/dist/agent/shell-ast.d.ts +11 -0
- package/dist/agent/shell-ast.js +204 -0
- package/dist/agent/shell-session.d.ts +14 -0
- package/dist/agent/shell-session.js +251 -40
- package/dist/agent/tool-schemas.js +26 -7
- package/dist/agent/tools/append_file.js +3 -1
- package/dist/agent/tools/apply_patch.js +44 -4
- package/dist/agent/tools/copy_file.js +26 -3
- package/dist/agent/tools/delete_file.js +22 -3
- package/dist/agent/tools/grep.js +35 -4
- package/dist/agent/tools/make_dir.js +3 -1
- package/dist/agent/tools/move_path.d.ts +7 -0
- package/dist/agent/tools/move_path.js +31 -5
- package/dist/agent/tools/read_file.js +63 -3
- package/dist/agent/tools/read_many.js +21 -3
- package/dist/agent/tools/readers.d.ts +53 -1
- package/dist/agent/tools/readers.js +236 -26
- package/dist/agent/tools/replace_in_file.js +38 -5
- package/dist/agent/tools/shell.js +2 -2
- package/dist/agent/tools/types.d.ts +26 -0
- package/dist/agent/tools/validate.d.ts +15 -2
- package/dist/agent/tools/validate.js +66 -3
- package/dist/agent/tools/write_file.js +3 -1
- package/dist/app.d.ts +2 -1
- package/dist/app.js +526 -85
- package/dist/cli-main.js +363 -0
- package/dist/cli.js +397 -337
- package/dist/commands/about.js +1 -1
- package/dist/commands/clear.d.ts +1 -0
- package/dist/commands/clear.js +1 -1
- package/dist/commands/compact.d.ts +12 -0
- package/dist/commands/compact.js +14 -2
- package/dist/commands/context.js +5 -4
- package/dist/commands/index.js +2 -0
- package/dist/commands/jobs.js +3 -2
- package/dist/commands/kill.js +3 -1
- package/dist/commands/login.d.ts +2 -2
- package/dist/commands/login.js +15 -15
- package/dist/commands/model.d.ts +1 -13
- package/dist/commands/model.js +6 -38
- package/dist/commands/provider.d.ts +1 -15
- package/dist/commands/provider.js +4 -22
- package/dist/commands/skills.js +34 -4
- package/dist/commands/threads.d.ts +9 -0
- package/dist/commands/threads.js +26 -0
- package/dist/config/store.d.ts +21 -0
- package/dist/config/store.js +47 -9
- package/dist/config/trust.d.ts +9 -0
- package/dist/config/trust.js +41 -2
- package/dist/headless.d.ts +7 -0
- package/dist/headless.js +213 -0
- package/dist/index.js +19 -3
- package/dist/lib/debug.d.ts +2 -0
- package/dist/lib/debug.js +22 -0
- package/dist/lib/diagnostics.d.ts +19 -0
- package/dist/lib/diagnostics.js +32 -6
- package/dist/lib/highlight-subset.d.ts +21 -0
- package/dist/lib/highlight-subset.js +88 -0
- package/dist/lib/lifecycle.d.ts +5 -0
- package/dist/lib/lifecycle.js +62 -0
- package/dist/lib/markdown.js +22 -4
- package/dist/providers/deepseek.js +1 -1
- package/dist/providers/openaiCompatible.d.ts +24 -2
- package/dist/providers/openaiCompatible.js +20 -6
- package/dist/providers/spec.d.ts +12 -0
- package/dist/providers/spec.js +29 -0
- package/dist/session/log.d.ts +14 -2
- package/dist/session/log.js +56 -27
- package/dist/session/projection.d.ts +34 -1
- package/dist/session/projection.js +315 -46
- package/dist/skills/manager.d.ts +15 -0
- package/dist/skills/manager.js +135 -18
- package/dist/types.d.ts +15 -0
- package/dist/ui/StatusBar.js +1 -1
- package/package.json +3 -2
- package/src/agent/approval-json.ts +103 -0
- package/src/agent/approval-native.ts +168 -0
- package/src/agent/approval-store.ts +38 -0
- package/src/agent/approval.ts +58 -11
- package/src/agent/compaction.ts +62 -17
- package/src/agent/guards.ts +1049 -25
- package/src/agent/policy/defaults.ts +34 -0
- package/src/agent/policy/egress.ts +335 -0
- package/src/agent/process-tree.ts +105 -23
- package/src/agent/protocol.ts +187 -39
- package/src/agent/registry.ts +186 -14
- package/src/agent/runner.ts +50 -7
- package/src/agent/shell-ast.ts +227 -0
- package/src/agent/shell-session.ts +265 -41
- package/src/agent/tool-schemas.ts +26 -7
- package/src/agent/tools/append_file.ts +3 -1
- package/src/agent/tools/apply_patch.ts +45 -4
- package/src/agent/tools/copy_file.ts +27 -3
- package/src/agent/tools/delete_file.ts +22 -3
- package/src/agent/tools/grep.ts +36 -4
- package/src/agent/tools/make_dir.ts +3 -1
- package/src/agent/tools/move_path.ts +38 -5
- package/src/agent/tools/read_file.ts +64 -3
- package/src/agent/tools/read_many.ts +21 -3
- package/src/agent/tools/readers.ts +289 -26
- package/src/agent/tools/replace_in_file.ts +39 -5
- package/src/agent/tools/shell.ts +2 -2
- package/src/agent/tools/types.ts +43 -1
- package/src/agent/tools/validate.ts +73 -4
- package/src/agent/tools/write_file.ts +3 -1
- package/src/app.ts +533 -82
- package/src/{cli.ts → cli-main.ts} +34 -6
- package/src/commands/about.ts +1 -1
- package/src/commands/clear.ts +1 -1
- package/src/commands/compact.ts +14 -2
- package/src/commands/context.ts +5 -4
- package/src/commands/index.ts +2 -0
- package/src/commands/jobs.ts +3 -2
- package/src/commands/kill.ts +3 -1
- package/src/commands/login.ts +15 -15
- package/src/commands/model.ts +6 -38
- package/src/commands/provider.ts +4 -22
- package/src/commands/skills.ts +34 -4
- package/src/commands/threads.ts +28 -0
- package/src/config/store.ts +47 -9
- package/src/config/trust.ts +45 -2
- package/src/headless.ts +225 -0
- package/src/index.ts +19 -3
- package/src/lib/debug.ts +24 -0
- package/src/lib/diagnostics.ts +32 -6
- package/src/lib/highlight-subset.ts +93 -0
- package/src/lib/lifecycle.ts +69 -0
- package/src/lib/markdown.ts +22 -4
- package/src/providers/deepseek.ts +1 -1
- package/src/providers/openaiCompatible.ts +47 -10
- package/src/providers/spec.ts +42 -0
- package/src/session/log.ts +70 -27
- package/src/session/projection.ts +360 -47
- package/src/skills/manager.ts +140 -18
- package/src/types/highlight-shims.d.ts +14 -0
- package/src/types.ts +16 -1
- package/src/ui/StatusBar.ts +1 -1
- package/tsconfig.json +1 -0
- /package/dist/{cli.d.ts → cli-main.d.ts} +0 -0
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
import { fetchJson, streamSSE } from "../lib/http.js";
|
|
2
2
|
import { finalizeToolCalls, mergeToolCallDelta, type ToolCallAccumulator } from "../lib/native-tools.js";
|
|
3
|
+
import { buildHeaders, buildRequestUrl, type RequestSpec } from "./spec.js";
|
|
4
|
+
|
|
5
|
+
export interface ModelInfo {
|
|
6
|
+
id: string;
|
|
7
|
+
label?: string;
|
|
8
|
+
[key: string]: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface StreamOptions {
|
|
12
|
+
baseUrl: string;
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
chatPath?: string;
|
|
15
|
+
modelsPath?: string | null;
|
|
16
|
+
query?: Record<string, string>;
|
|
17
|
+
pathParams?: Record<string, string>;
|
|
18
|
+
authHeaderName?: string;
|
|
19
|
+
authPrefix?: string;
|
|
20
|
+
staticModels?: ModelInfo[];
|
|
21
|
+
extraHeaders?: Record<string, string>;
|
|
22
|
+
/** Legacy auth prefix, e.g. "Bearer". Prefer authPrefix for new callers. */
|
|
23
|
+
authHeader?: string;
|
|
24
|
+
reasoning?: "openai" | "openrouter" | "none" | string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function toRequestSpec(opts: StreamOptions): RequestSpec {
|
|
28
|
+
return {
|
|
29
|
+
baseUrl: trim(opts.baseUrl),
|
|
30
|
+
chatPath: opts.chatPath,
|
|
31
|
+
modelsPath: opts.modelsPath,
|
|
32
|
+
query: opts.query,
|
|
33
|
+
pathParams: opts.pathParams,
|
|
34
|
+
authHeaderName: opts.authHeaderName,
|
|
35
|
+
authPrefix: opts.authPrefix ?? (opts.authHeader !== undefined ? `${opts.authHeader} ` : undefined),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
3
38
|
/** Build a chat-completions body in the classic or the newer (compat) dialect. */
|
|
4
|
-
function buildBody(req, compat, opts, includeReasoning = true) {
|
|
39
|
+
function buildBody(req: any, compat: boolean, opts: StreamOptions, includeReasoning = true) {
|
|
5
40
|
const messages = [];
|
|
6
41
|
if (req.system)
|
|
7
42
|
messages.push({ role: "system", content: req.system });
|
|
@@ -46,19 +81,20 @@ function buildBody(req, compat, opts, includeReasoning = true) {
|
|
|
46
81
|
}
|
|
47
82
|
return body;
|
|
48
83
|
}
|
|
49
|
-
export async function* streamChatCompletion(req, opts) {
|
|
84
|
+
export async function* streamChatCompletion(req: any, opts: StreamOptions) {
|
|
50
85
|
const hasReasoning = Boolean(req.reasoningEffort && req.reasoningEffort !== "auto" && opts.reasoning && opts.reasoning !== "none");
|
|
86
|
+
const spec = toRequestSpec(opts);
|
|
51
87
|
const send = async (compat, includeReasoning = hasReasoning) => {
|
|
52
|
-
const headers = {
|
|
88
|
+
const headers: Record<string, string> = {
|
|
53
89
|
"content-type": "application/json",
|
|
54
90
|
accept: "text/event-stream",
|
|
55
91
|
...(opts.extraHeaders ?? {}),
|
|
56
92
|
};
|
|
57
93
|
if (opts.apiKey)
|
|
58
|
-
headers
|
|
94
|
+
Object.assign(headers, buildHeaders(spec, opts.apiKey));
|
|
59
95
|
if (req.clientRequestId)
|
|
60
96
|
headers["idempotency-key"] = req.clientRequestId;
|
|
61
|
-
return await fetch(
|
|
97
|
+
return await fetch(buildRequestUrl(spec, opts.chatPath ?? "/chat/completions"), {
|
|
62
98
|
method: "POST",
|
|
63
99
|
headers,
|
|
64
100
|
body: JSON.stringify(buildBody(req, compat, opts, includeReasoning)),
|
|
@@ -128,15 +164,16 @@ export async function* streamChatCompletion(req, opts) {
|
|
|
128
164
|
const calls = finalizeToolCalls(toolCalls);
|
|
129
165
|
yield calls.length > 0 ? { delta: "", done: true, usage, toolCalls: calls } : { delta: "", done: true, usage };
|
|
130
166
|
}
|
|
131
|
-
export async function listModelsHttp(opts) {
|
|
167
|
+
export async function listModelsHttp(opts: StreamOptions) {
|
|
132
168
|
const staticModels = opts.staticModels ?? [];
|
|
169
|
+
if (opts.modelsPath === null)
|
|
170
|
+
return staticModels;
|
|
133
171
|
if (!opts.apiKey && staticModels.length)
|
|
134
172
|
return staticModels;
|
|
135
173
|
try {
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
const json = await fetchJson(trim(opts.baseUrl) + "/models", { headers });
|
|
174
|
+
const spec = toRequestSpec(opts);
|
|
175
|
+
const headers = opts.apiKey ? buildHeaders(spec, opts.apiKey) : {};
|
|
176
|
+
const json = await fetchJson(buildRequestUrl(spec, opts.modelsPath ?? "/models"), { headers });
|
|
140
177
|
const ids = (json.data ?? [])
|
|
141
178
|
.map((m) => m.id)
|
|
142
179
|
.filter((id) => typeof id === "string" && id.length > 0);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export interface RequestSpec {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
chatPath?: string;
|
|
4
|
+
modelsPath?: string | null;
|
|
5
|
+
query?: Record<string, string>;
|
|
6
|
+
pathParams?: Record<string, string>;
|
|
7
|
+
authHeaderName?: string;
|
|
8
|
+
authPrefix?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const ENV_MAP: Record<string, string> = {
|
|
12
|
+
region: "AWS_REGION",
|
|
13
|
+
account_id: "CLOUDFLARE_ACCOUNT_ID",
|
|
14
|
+
project_id: "GOOGLE_CLOUD_PROJECT",
|
|
15
|
+
deployment: "AZURE_OPENAI_DEPLOYMENT",
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export function resolveBaseUrl(spec: RequestSpec): string {
|
|
19
|
+
return spec.baseUrl.replace(/\{(\w+)\}/g, (_, key) => {
|
|
20
|
+
const envName = ENV_MAP[key];
|
|
21
|
+
const value = envName ? process.env[envName] : undefined;
|
|
22
|
+
if (!value)
|
|
23
|
+
throw new Error(`Missing ${envName ?? key} for placeholder {${key}}`);
|
|
24
|
+
return value;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function buildRequestUrl(spec: RequestSpec, path: string, params?: Record<string, string>): string {
|
|
29
|
+
const base = resolveBaseUrl(spec);
|
|
30
|
+
const merged = { ...spec.pathParams, ...params };
|
|
31
|
+
const resolvedPath = path.replace(/\{(\w+)\}/g, (_, key) => merged[key] ?? `{${key}}`);
|
|
32
|
+
const query = spec.query ? "?" + new URLSearchParams(spec.query).toString() : "";
|
|
33
|
+
return base + resolvedPath + query;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildHeaders(spec: RequestSpec, apiKey: string, extra?: Record<string, string>): Record<string, string> {
|
|
37
|
+
const headers: Record<string, string> = {
|
|
38
|
+
[spec.authHeaderName ?? "authorization"]: (spec.authPrefix ?? "Bearer ") + apiKey,
|
|
39
|
+
...extra,
|
|
40
|
+
};
|
|
41
|
+
return headers;
|
|
42
|
+
}
|
package/src/session/log.ts
CHANGED
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* FASTCODE_SESSION_CACHE_MB=N sessions cache cap in MB (default 256)
|
|
11
11
|
* FASTCODE_FSYNC=0|1 force checkpoint fsync off/on
|
|
12
12
|
*/
|
|
13
|
-
import { appendFileSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, rmSync, statSync,
|
|
14
|
-
import {
|
|
13
|
+
import { appendFileSync, closeSync, existsSync, fsyncSync, mkdirSync, openSync, readdirSync, readFileSync, readSync, rmSync, statSync, writeSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
15
|
import { getPaths } from "../config/paths.js";
|
|
16
|
+
import { buildProjection, writeProjection } from "./projection.js";
|
|
16
17
|
|
|
17
18
|
const NL = String.fromCharCode(10);
|
|
18
19
|
|
|
@@ -34,6 +35,18 @@ export interface SessionSummary {
|
|
|
34
35
|
lastTs: number;
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
/** Reserved slot for conversation compaction at the exit save point. */
|
|
39
|
+
export interface SessionCompactionSlot {
|
|
40
|
+
source?: "local" | "server" | "none";
|
|
41
|
+
summaryRef?: string | null;
|
|
42
|
+
pending?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SessionCloseInfo {
|
|
46
|
+
reason?: "exit" | "signal" | "fatal" | "close";
|
|
47
|
+
compaction?: SessionCompactionSlot;
|
|
48
|
+
}
|
|
49
|
+
|
|
37
50
|
export function sessionCacheLimitBytes(): number {
|
|
38
51
|
const mb = Number(process.env["FASTCODE_SESSION_CACHE_MB"]);
|
|
39
52
|
return (Number.isFinite(mb) && mb > 0 ? mb : 256) * 1024 * 1024;
|
|
@@ -90,6 +103,24 @@ function writeLine(file: string, line: string, type: string): void {
|
|
|
90
103
|
}
|
|
91
104
|
}
|
|
92
105
|
|
|
106
|
+
function fsyncPath(file: string): void {
|
|
107
|
+
if (!existsSync(file))
|
|
108
|
+
return;
|
|
109
|
+
try {
|
|
110
|
+
const fd = openSync(file, "r");
|
|
111
|
+
try {
|
|
112
|
+
fsyncSync(fd);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
closeSync(fd);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// FUSE / read-only filesystems may reject fsync; the append is still
|
|
120
|
+
// best effort and the caller already caught close-level failures.
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
93
124
|
function countLines(file: string): number {
|
|
94
125
|
if (!existsSync(file))
|
|
95
126
|
return 0;
|
|
@@ -130,10 +161,25 @@ function openLog(id: string | undefined, file: string, meta: Record<string, any>
|
|
|
130
161
|
count() {
|
|
131
162
|
return seq;
|
|
132
163
|
},
|
|
133
|
-
close() {
|
|
134
|
-
append({
|
|
164
|
+
close(info: SessionCloseInfo = {}) {
|
|
165
|
+
append({
|
|
166
|
+
type: "session_end",
|
|
167
|
+
reason: info.reason ?? "close",
|
|
168
|
+
// Reserved extension point: future compaction can fill this
|
|
169
|
+
// slot without changing the session_end event shape.
|
|
170
|
+
compaction: {
|
|
171
|
+
source: info.compaction?.source ?? "none",
|
|
172
|
+
summaryRef: info.compaction?.summaryRef ?? null,
|
|
173
|
+
pending: info.compaction?.pending ?? false,
|
|
174
|
+
},
|
|
175
|
+
});
|
|
135
176
|
closed = true;
|
|
136
177
|
try {
|
|
178
|
+
// Snapshot + manifest are written while the facts still exist;
|
|
179
|
+
// pruning later keeps this verified copy.
|
|
180
|
+
ensureProjection(file);
|
|
181
|
+
fsyncPath(file);
|
|
182
|
+
fsyncPath(projectionPath(file));
|
|
137
183
|
pruneSessions();
|
|
138
184
|
}
|
|
139
185
|
catch {
|
|
@@ -143,6 +189,22 @@ function openLog(id: string | undefined, file: string, meta: Record<string, any>
|
|
|
143
189
|
};
|
|
144
190
|
}
|
|
145
191
|
|
|
192
|
+
/** Summary files referenced by older compacted facts in this session. */
|
|
193
|
+
export function staleSummaryRefs(file: string): string[] {
|
|
194
|
+
let facts: any[];
|
|
195
|
+
try {
|
|
196
|
+
facts = readSession(file);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
return [];
|
|
200
|
+
}
|
|
201
|
+
const compacted = facts.filter((fact) => fact?.type === "compacted");
|
|
202
|
+
const latest = compacted.at(-1)?.summaryRef;
|
|
203
|
+
return Array.from(new Set(compacted
|
|
204
|
+
.map((fact) => fact.summaryRef)
|
|
205
|
+
.filter((ref): ref is string => typeof ref === "string" && ref.length > 0 && ref !== latest)));
|
|
206
|
+
}
|
|
207
|
+
|
|
146
208
|
export function createSessionLog(meta: Record<string, any> = {}) {
|
|
147
209
|
const { sessions } = getPaths();
|
|
148
210
|
mkdirSync(sessions, { recursive: true });
|
|
@@ -329,32 +391,13 @@ export function latestUnclosedSession(): SessionSummary | undefined {
|
|
|
329
391
|
}
|
|
330
392
|
|
|
331
393
|
function ensureProjection(file: string): void {
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
394
|
+
// Always refresh from the facts that still exist: a projection written at
|
|
395
|
+
// an earlier checkpoint may be stale by the time we close or prune. If the
|
|
396
|
+
// JSONL is already gone, leave the verified projection untouched.
|
|
335
397
|
const entries = readSession(file);
|
|
336
398
|
if (entries.length === 0)
|
|
337
399
|
return;
|
|
338
|
-
|
|
339
|
-
const lastUser = [...entries].reverse().find((entry) => entry.type === "message" && entry.role === "user");
|
|
340
|
-
const lastAssistant = [...entries].reverse().find((entry) => entry.type === "message" && entry.role === "assistant");
|
|
341
|
-
const payload = {
|
|
342
|
-
version: 1,
|
|
343
|
-
kind: "pruned_session",
|
|
344
|
-
source: basename(file),
|
|
345
|
-
createdAt: new Date().toISOString(),
|
|
346
|
-
summary: {
|
|
347
|
-
cwd: summary.cwd,
|
|
348
|
-
providerId: summary.providerId,
|
|
349
|
-
model: summary.model,
|
|
350
|
-
turns: summary.turns,
|
|
351
|
-
messages: summary.messages,
|
|
352
|
-
activeFiles: summary.activeFiles.slice(0, 200),
|
|
353
|
-
lastUser: typeof lastUser?.content === "string" ? lastUser.content.slice(0, 2000) : "",
|
|
354
|
-
lastAssistant: typeof lastAssistant?.content === "string" ? lastAssistant.content.slice(0, 2000) : "",
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
writeFileSync(target, JSON.stringify(payload, null, 2), "utf8");
|
|
400
|
+
writeProjection(file, buildProjection(entries), entries);
|
|
358
401
|
}
|
|
359
402
|
|
|
360
403
|
export function pruneSessions(limit = sessionCacheLimitBytes()): number {
|