frizz 0.1.0 → 0.2.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/README.md +121 -63
- package/dist/dev-child.js +631 -502
- package/dist/frizz.js +191 -66
- package/package.json +1 -1
package/dist/dev-child.js
CHANGED
|
@@ -568,6 +568,124 @@ var init_project_identity = __esm({
|
|
|
568
568
|
}
|
|
569
569
|
});
|
|
570
570
|
|
|
571
|
+
// packages/server/src/project-root.ts
|
|
572
|
+
import { createHash as createHash2, randomUUID as randomUUID3 } from "node:crypto";
|
|
573
|
+
import { closeSync as closeSync2, existsSync as existsSync2, fsyncSync as fsyncSync2, mkdirSync as mkdirSync2, openSync as openSync2, readFileSync as readFileSync3, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
574
|
+
import { homedir as homedir3 } from "node:os";
|
|
575
|
+
import { dirname as dirname2, join as join3, parse, resolve as resolve2 } from "node:path";
|
|
576
|
+
function projectIdPath(root) {
|
|
577
|
+
return join3(root, FRIZZ_DIR, ID_FILE);
|
|
578
|
+
}
|
|
579
|
+
function readProjectIdFile(root) {
|
|
580
|
+
let raw2;
|
|
581
|
+
try {
|
|
582
|
+
raw2 = readFileSync3(projectIdPath(root), "utf8");
|
|
583
|
+
} catch {
|
|
584
|
+
return void 0;
|
|
585
|
+
}
|
|
586
|
+
try {
|
|
587
|
+
return validateProjectId(raw2.trim());
|
|
588
|
+
} catch {
|
|
589
|
+
throw new Error(`${projectIdPath(root)} is invalid; expected exactly one UUID`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
function writeProjectIdFile(root, id) {
|
|
593
|
+
const dir = join3(root, FRIZZ_DIR);
|
|
594
|
+
mkdirSync2(dir, { recursive: true });
|
|
595
|
+
const ignore = join3(dir, SELF_IGNORE);
|
|
596
|
+
if (!existsSync2(ignore)) {
|
|
597
|
+
try {
|
|
598
|
+
writeFileSync2(ignore, "*\n", { flag: "wx" });
|
|
599
|
+
} catch {
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
const path = projectIdPath(root);
|
|
603
|
+
const temp = join3(dir, `.${ID_FILE}.${process.pid}.${randomUUID3()}.tmp`);
|
|
604
|
+
let fd;
|
|
605
|
+
try {
|
|
606
|
+
fd = openSync2(temp, "wx", 384);
|
|
607
|
+
writeFileSync2(fd, `${id}
|
|
608
|
+
`, "utf8");
|
|
609
|
+
fsyncSync2(fd);
|
|
610
|
+
closeSync2(fd);
|
|
611
|
+
fd = void 0;
|
|
612
|
+
renameSync2(temp, path);
|
|
613
|
+
} catch (error) {
|
|
614
|
+
if (fd !== void 0) {
|
|
615
|
+
try {
|
|
616
|
+
closeSync2(fd);
|
|
617
|
+
} catch {
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
try {
|
|
621
|
+
rmSync2(temp, { force: true });
|
|
622
|
+
} catch {
|
|
623
|
+
}
|
|
624
|
+
throw error;
|
|
625
|
+
}
|
|
626
|
+
return id;
|
|
627
|
+
}
|
|
628
|
+
function projectRootLockName(root) {
|
|
629
|
+
return `identity-path-${createHash2("sha256").update(root).digest("hex")}.lock`;
|
|
630
|
+
}
|
|
631
|
+
function ensureProjectIdFile(root, home = homedir3(), seed) {
|
|
632
|
+
const existing = readProjectIdFile(root);
|
|
633
|
+
if (existing) return existing;
|
|
634
|
+
const release = acquireNamedLaunchLockSync(home, projectRootLockName(root));
|
|
635
|
+
try {
|
|
636
|
+
const raced = readProjectIdFile(root);
|
|
637
|
+
if (raced) return raced;
|
|
638
|
+
return writeProjectIdFile(root, seed ? validateProjectId(seed) : randomUUID3());
|
|
639
|
+
} finally {
|
|
640
|
+
release();
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function hasAny(dir, names) {
|
|
644
|
+
return names.some((name) => existsSync2(join3(dir, name)));
|
|
645
|
+
}
|
|
646
|
+
function discoverProjectRoot(cwd = process.cwd(), home = homedir3()) {
|
|
647
|
+
let dir;
|
|
648
|
+
try {
|
|
649
|
+
dir = resolve2(cwd);
|
|
650
|
+
} catch {
|
|
651
|
+
return resolve2(cwd);
|
|
652
|
+
}
|
|
653
|
+
const stop = resolve2(home);
|
|
654
|
+
const filesystemRoot = parse(dir).root;
|
|
655
|
+
for (let at = dir; ; at = dirname2(at)) {
|
|
656
|
+
if (at === stop || at === filesystemRoot) break;
|
|
657
|
+
if (existsSync2(projectIdPath(at))) return at;
|
|
658
|
+
if (hasAny(at, REPO_MARKERS)) return at;
|
|
659
|
+
if (hasAny(at, PROJECT_MARKERS)) return at;
|
|
660
|
+
if (dirname2(at) === at) break;
|
|
661
|
+
}
|
|
662
|
+
return dir;
|
|
663
|
+
}
|
|
664
|
+
var FRIZZ_DIR, ID_FILE, SELF_IGNORE, REPO_MARKERS, PROJECT_MARKERS;
|
|
665
|
+
var init_project_root = __esm({
|
|
666
|
+
"packages/server/src/project-root.ts"() {
|
|
667
|
+
"use strict";
|
|
668
|
+
init_project_identity();
|
|
669
|
+
FRIZZ_DIR = ".frizz";
|
|
670
|
+
ID_FILE = ".id";
|
|
671
|
+
SELF_IGNORE = ".gitignore";
|
|
672
|
+
REPO_MARKERS = [".git", ".jj", ".hg", ".svn"];
|
|
673
|
+
PROJECT_MARKERS = [
|
|
674
|
+
"package.json",
|
|
675
|
+
"pyproject.toml",
|
|
676
|
+
"go.mod",
|
|
677
|
+
"Cargo.toml",
|
|
678
|
+
"deno.json",
|
|
679
|
+
"deno.jsonc",
|
|
680
|
+
"composer.json",
|
|
681
|
+
"Gemfile",
|
|
682
|
+
"pom.xml",
|
|
683
|
+
"build.gradle",
|
|
684
|
+
"Makefile"
|
|
685
|
+
];
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
|
|
571
689
|
// packages/server/src/sqlite-quiet.ts
|
|
572
690
|
function isSqliteExperimentalNotice(warning, type) {
|
|
573
691
|
const name = typeof warning === "string" ? type : warning?.name;
|
|
@@ -795,39 +913,39 @@ var init_sqlite = __esm({
|
|
|
795
913
|
|
|
796
914
|
// packages/server/src/migrate-fray.ts
|
|
797
915
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
798
|
-
import { existsSync as
|
|
799
|
-
import { homedir as
|
|
800
|
-
import { join as
|
|
916
|
+
import { existsSync as existsSync3, lstatSync, readdirSync, realpathSync as realpathSync2, renameSync as renameSync3, rmdirSync } from "node:fs";
|
|
917
|
+
import { homedir as homedir4 } from "node:os";
|
|
918
|
+
import { join as join4, resolve as resolve3 } from "node:path";
|
|
801
919
|
function xdg2(env, name) {
|
|
802
920
|
const value = env[name];
|
|
803
921
|
return value && (value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value)) ? value : void 0;
|
|
804
922
|
}
|
|
805
923
|
function movesFor(env, platform3, home) {
|
|
806
|
-
const moves = [{ from:
|
|
924
|
+
const moves = [{ from: join4(home, ".fray"), to: join4(home, ".frizz") }];
|
|
807
925
|
if (platform3 === "win32") {
|
|
808
|
-
const local = env.LOCALAPPDATA ||
|
|
809
|
-
moves.push({ from:
|
|
926
|
+
const local = env.LOCALAPPDATA || join4(env.USERPROFILE || home, "AppData", "Local");
|
|
927
|
+
moves.push({ from: join4(local, "Fray"), to: join4(local, "Frizz") });
|
|
810
928
|
} else if (platform3 === "darwin") {
|
|
811
|
-
const support =
|
|
812
|
-
moves.push({ from:
|
|
813
|
-
moves.push({ from:
|
|
929
|
+
const support = join4(home, "Library", "Application Support");
|
|
930
|
+
moves.push({ from: join4(support, "Fray"), to: join4(support, "Frizz") });
|
|
931
|
+
moves.push({ from: join4(home, "Library", "Caches", "Fray"), to: join4(home, "Library", "Caches", "Frizz") });
|
|
814
932
|
} else {
|
|
815
|
-
moves.push({ from:
|
|
816
|
-
moves.push({ from:
|
|
817
|
-
moves.push({ from:
|
|
933
|
+
moves.push({ from: join4(home, ".local", "share", "fray"), to: join4(home, ".local", "share", "frizz") });
|
|
934
|
+
moves.push({ from: join4(home, ".local", "state", "fray"), to: join4(home, ".local", "state", "frizz") });
|
|
935
|
+
moves.push({ from: join4(home, ".cache", "fray"), to: join4(home, ".cache", "frizz") });
|
|
818
936
|
}
|
|
819
937
|
for (const name of ["XDG_DATA_HOME", "XDG_STATE_HOME", "XDG_CACHE_HOME"]) {
|
|
820
938
|
const base = xdg2(env, name);
|
|
821
|
-
if (base) moves.push({ from:
|
|
939
|
+
if (base) moves.push({ from: join4(base, "fray"), to: join4(base, "frizz") });
|
|
822
940
|
}
|
|
823
941
|
return moves;
|
|
824
942
|
}
|
|
825
943
|
function migrateFrayGlobalRoots(options = {}) {
|
|
826
944
|
const env = options.env ?? process.env;
|
|
827
945
|
const platform3 = options.platform ?? process.platform;
|
|
828
|
-
const home = options.home ??
|
|
829
|
-
const exists = options.exists ??
|
|
830
|
-
const rename2 = options.rename ??
|
|
946
|
+
const home = options.home ?? homedir4();
|
|
947
|
+
const exists = options.exists ?? existsSync3;
|
|
948
|
+
const rename2 = options.rename ?? renameSync3;
|
|
831
949
|
const merge = options.merge ?? mergeInto;
|
|
832
950
|
const moved = [];
|
|
833
951
|
for (const move of movesFor(env, platform3, home)) {
|
|
@@ -847,10 +965,10 @@ function migrateFrayGlobalRoots(options = {}) {
|
|
|
847
965
|
function mergeInto(from, to) {
|
|
848
966
|
let moved = false;
|
|
849
967
|
for (const entry of readdirSync(from, { withFileTypes: true })) {
|
|
850
|
-
const src =
|
|
851
|
-
const dst =
|
|
852
|
-
if (!
|
|
853
|
-
|
|
968
|
+
const src = join4(from, entry.name);
|
|
969
|
+
const dst = join4(to, entry.name);
|
|
970
|
+
if (!existsSync3(dst)) {
|
|
971
|
+
renameSync3(src, dst);
|
|
854
972
|
moved = true;
|
|
855
973
|
continue;
|
|
856
974
|
}
|
|
@@ -863,12 +981,12 @@ function mergeInto(from, to) {
|
|
|
863
981
|
return moved;
|
|
864
982
|
}
|
|
865
983
|
function migrateFrayProjectDir(projectDir) {
|
|
866
|
-
const from =
|
|
867
|
-
const to =
|
|
984
|
+
const from = join4(projectDir, ".fray");
|
|
985
|
+
const to = join4(projectDir, ".frizz");
|
|
868
986
|
try {
|
|
869
987
|
if (!lstatSync(from).isDirectory()) return false;
|
|
870
|
-
if (!
|
|
871
|
-
|
|
988
|
+
if (!existsSync3(to)) {
|
|
989
|
+
renameSync3(from, to);
|
|
872
990
|
return true;
|
|
873
991
|
}
|
|
874
992
|
return lstatSync(to).isDirectory() ? mergeInto(from, to) : false;
|
|
@@ -905,8 +1023,8 @@ function writeId(dir, scope, id) {
|
|
|
905
1023
|
return readId(dir, scope, CURRENT_KEY) === id;
|
|
906
1024
|
}
|
|
907
1025
|
function hasBoard(id, home) {
|
|
908
|
-
const db =
|
|
909
|
-
if (!
|
|
1026
|
+
const db = join4(projectStateDir(id, home), "ui.db");
|
|
1027
|
+
if (!existsSync3(db)) return false;
|
|
910
1028
|
let sql;
|
|
911
1029
|
try {
|
|
912
1030
|
sql = new Database(db, { readonly: true });
|
|
@@ -930,7 +1048,7 @@ function linkedWorktreeScopes(dir) {
|
|
|
930
1048
|
env: { ...process.env, LC_ALL: "C" },
|
|
931
1049
|
stdio: ["ignore", "pipe", "ignore"]
|
|
932
1050
|
}).trim();
|
|
933
|
-
return realpathSync2(
|
|
1051
|
+
return realpathSync2(resolve3(dir, raw2));
|
|
934
1052
|
} catch {
|
|
935
1053
|
return void 0;
|
|
936
1054
|
}
|
|
@@ -939,8 +1057,8 @@ function linkedWorktreeScopes(dir) {
|
|
|
939
1057
|
const commonGitDir = gitPath("--git-common-dir");
|
|
940
1058
|
if (!gitDir || !commonGitDir || gitDir === commonGitDir) return void 0;
|
|
941
1059
|
return {
|
|
942
|
-
legacy: ["--file",
|
|
943
|
-
current: ["--file",
|
|
1060
|
+
legacy: ["--file", join4(gitDir, "fray.config")],
|
|
1061
|
+
current: ["--file", join4(gitDir, "frizz.config")]
|
|
944
1062
|
};
|
|
945
1063
|
}
|
|
946
1064
|
function adopt(dir, legacy, current, home) {
|
|
@@ -977,15 +1095,14 @@ var init_migrate_fray = __esm({
|
|
|
977
1095
|
|
|
978
1096
|
// packages/server/src/project.ts
|
|
979
1097
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
980
|
-
import { mkdirSync as
|
|
981
|
-
import { homedir as
|
|
982
|
-
import { basename, join as
|
|
983
|
-
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
1098
|
+
import { mkdirSync as mkdirSync3, realpathSync as realpathSync3 } from "node:fs";
|
|
1099
|
+
import { homedir as homedir5, tmpdir } from "node:os";
|
|
1100
|
+
import { basename, join as join5, resolve as resolve4 } from "node:path";
|
|
984
1101
|
function trustedLocalFileRoots(project) {
|
|
985
|
-
return [project.dir, tmpdir(), "/tmp",
|
|
1102
|
+
return [project.dir, tmpdir(), "/tmp", resolve4(homedir5(), "Screenshots"), join5(project.stateDir, "attachments")];
|
|
986
1103
|
}
|
|
987
1104
|
function openableFileRoots(project) {
|
|
988
|
-
return [
|
|
1105
|
+
return [homedir5(), ...trustedLocalFileRoots(project)];
|
|
989
1106
|
}
|
|
990
1107
|
function isNotGitRepositoryError(error) {
|
|
991
1108
|
if (!error || typeof error !== "object" || !("stderr" in error)) return false;
|
|
@@ -1001,15 +1118,23 @@ function resolveProjectDir(cwd = process.cwd()) {
|
|
|
1001
1118
|
}).trim();
|
|
1002
1119
|
return realpathSync3(root);
|
|
1003
1120
|
} catch (error) {
|
|
1004
|
-
if (!isNotGitRepositoryError(error)
|
|
1121
|
+
if (!isNotGitRepositoryError(error) && !isMissingGitBinary(error)) {
|
|
1122
|
+
throw new Error("unable to resolve Git repository root");
|
|
1123
|
+
}
|
|
1124
|
+
const root = discoverProjectRoot(cwd);
|
|
1005
1125
|
try {
|
|
1006
|
-
return realpathSync3(
|
|
1126
|
+
return realpathSync3(root);
|
|
1007
1127
|
} catch {
|
|
1008
|
-
return
|
|
1128
|
+
return resolve4(root);
|
|
1009
1129
|
}
|
|
1010
1130
|
}
|
|
1011
1131
|
}
|
|
1012
|
-
function
|
|
1132
|
+
function isMissingGitBinary(error) {
|
|
1133
|
+
const code = error?.code;
|
|
1134
|
+
return code === "ENOENT" || code === "EACCES";
|
|
1135
|
+
}
|
|
1136
|
+
function resolveProjectIdentity(dir, home = homedir5()) {
|
|
1137
|
+
let insideWorktree = false;
|
|
1013
1138
|
try {
|
|
1014
1139
|
const inside = execFileSync4("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
1015
1140
|
cwd: dir,
|
|
@@ -1018,12 +1143,15 @@ function resolveProjectIdentity(dir, home = homedir4()) {
|
|
|
1018
1143
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1019
1144
|
}).trim();
|
|
1020
1145
|
if (inside !== "true") throw new Error("Git directory is not a worktree");
|
|
1146
|
+
insideWorktree = true;
|
|
1021
1147
|
} catch (error) {
|
|
1022
|
-
if (!isNotGitRepositoryError(error)
|
|
1023
|
-
|
|
1148
|
+
if (!isNotGitRepositoryError(error) && !isMissingGitBinary(error)) {
|
|
1149
|
+
throw new Error("unable to inspect Git repository identity");
|
|
1150
|
+
}
|
|
1024
1151
|
}
|
|
1025
|
-
const
|
|
1026
|
-
|
|
1152
|
+
const git = insideWorktree ? resolveGitProjectIdentity(dir, home) : void 0;
|
|
1153
|
+
const root = git?.root ?? dir;
|
|
1154
|
+
return { id: ensureProjectIdFile(root, home, git?.id), scope: git?.scope ?? "repository", root };
|
|
1027
1155
|
}
|
|
1028
1156
|
function cwdSlug(absPath) {
|
|
1029
1157
|
return absPath.replace(/[/.]/g, "-");
|
|
@@ -1054,7 +1182,7 @@ function resolveProjectLabel(dir) {
|
|
|
1054
1182
|
return null;
|
|
1055
1183
|
}
|
|
1056
1184
|
}
|
|
1057
|
-
function resolveProject(cwd = process.cwd(), home =
|
|
1185
|
+
function resolveProject(cwd = process.cwd(), home = homedir5(), env = process.env, { migrate = false } = {}) {
|
|
1058
1186
|
if (migrate) migrateFrayGlobalRoots({ env, home });
|
|
1059
1187
|
const projectDir = resolveProjectDir(cwd);
|
|
1060
1188
|
if (migrate) migrateFrayProjectId(projectDir, { home });
|
|
@@ -1063,7 +1191,7 @@ function resolveProject(cwd = process.cwd(), home = homedir4(), env = process.en
|
|
|
1063
1191
|
if (migrate) migrateFrayProjectDir(dir);
|
|
1064
1192
|
const id = identity.id;
|
|
1065
1193
|
const stateDir = projectStateDir(id, home);
|
|
1066
|
-
|
|
1194
|
+
mkdirSync3(stateDir, { recursive: true });
|
|
1067
1195
|
const name = basename(dir) || dir;
|
|
1068
1196
|
const target = {
|
|
1069
1197
|
projectId: id,
|
|
@@ -1082,10 +1210,10 @@ function resolveProject(cwd = process.cwd(), home = homedir4(), env = process.en
|
|
|
1082
1210
|
};
|
|
1083
1211
|
}
|
|
1084
1212
|
function permRequestDir(project) {
|
|
1085
|
-
return
|
|
1213
|
+
return join5(project.stateDir, "perm-requests");
|
|
1086
1214
|
}
|
|
1087
1215
|
function permMarkerPath(project, slug) {
|
|
1088
|
-
return
|
|
1216
|
+
return join5(permRequestDir(project), `${slug}.json`);
|
|
1089
1217
|
}
|
|
1090
1218
|
function projectLaunchTarget(project) {
|
|
1091
1219
|
return {
|
|
@@ -1118,25 +1246,26 @@ var init_project = __esm({
|
|
|
1118
1246
|
"packages/server/src/project.ts"() {
|
|
1119
1247
|
"use strict";
|
|
1120
1248
|
init_project_identity();
|
|
1249
|
+
init_project_root();
|
|
1121
1250
|
init_frizz_paths();
|
|
1122
1251
|
init_migrate_fray();
|
|
1123
1252
|
}
|
|
1124
1253
|
});
|
|
1125
1254
|
|
|
1126
1255
|
// packages/server/src/project-launch.ts
|
|
1127
|
-
import { createHash as
|
|
1256
|
+
import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
|
|
1128
1257
|
import {
|
|
1129
|
-
closeSync as
|
|
1130
|
-
fsyncSync as
|
|
1131
|
-
mkdirSync as
|
|
1132
|
-
openSync as
|
|
1133
|
-
readFileSync as
|
|
1134
|
-
renameSync as
|
|
1135
|
-
rmSync as
|
|
1258
|
+
closeSync as closeSync3,
|
|
1259
|
+
fsyncSync as fsyncSync3,
|
|
1260
|
+
mkdirSync as mkdirSync4,
|
|
1261
|
+
openSync as openSync3,
|
|
1262
|
+
readFileSync as readFileSync4,
|
|
1263
|
+
renameSync as renameSync4,
|
|
1264
|
+
rmSync as rmSync3,
|
|
1136
1265
|
statSync as statSync2,
|
|
1137
|
-
writeFileSync as
|
|
1266
|
+
writeFileSync as writeFileSync3
|
|
1138
1267
|
} from "node:fs";
|
|
1139
|
-
import { basename as basename2, dirname as
|
|
1268
|
+
import { basename as basename2, dirname as dirname3, isAbsolute, join as join6 } from "node:path";
|
|
1140
1269
|
function errorCode3(error) {
|
|
1141
1270
|
return error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
1142
1271
|
}
|
|
@@ -1146,40 +1275,40 @@ function validText(value, max = 4096) {
|
|
|
1146
1275
|
function syncDirectory2(path) {
|
|
1147
1276
|
let fd;
|
|
1148
1277
|
try {
|
|
1149
|
-
fd =
|
|
1150
|
-
|
|
1278
|
+
fd = openSync3(path, "r");
|
|
1279
|
+
fsyncSync3(fd);
|
|
1151
1280
|
} catch {
|
|
1152
1281
|
} finally {
|
|
1153
1282
|
if (fd !== void 0) {
|
|
1154
1283
|
try {
|
|
1155
|
-
|
|
1284
|
+
closeSync3(fd);
|
|
1156
1285
|
} catch {
|
|
1157
1286
|
}
|
|
1158
1287
|
}
|
|
1159
1288
|
}
|
|
1160
1289
|
}
|
|
1161
1290
|
function atomicJson(path, value) {
|
|
1162
|
-
|
|
1163
|
-
const temp =
|
|
1291
|
+
mkdirSync4(dirname3(path), { recursive: true, mode: 448 });
|
|
1292
|
+
const temp = join6(dirname3(path), `.${basename2(path)}.${process.pid}.${randomUUID4()}.tmp`);
|
|
1164
1293
|
let fd;
|
|
1165
1294
|
try {
|
|
1166
|
-
fd =
|
|
1167
|
-
|
|
1295
|
+
fd = openSync3(temp, "wx", 384);
|
|
1296
|
+
writeFileSync3(fd, `${JSON.stringify(value)}
|
|
1168
1297
|
`, "utf8");
|
|
1169
|
-
|
|
1170
|
-
|
|
1298
|
+
fsyncSync3(fd);
|
|
1299
|
+
closeSync3(fd);
|
|
1171
1300
|
fd = void 0;
|
|
1172
|
-
|
|
1173
|
-
syncDirectory2(
|
|
1301
|
+
renameSync4(temp, path);
|
|
1302
|
+
syncDirectory2(dirname3(path));
|
|
1174
1303
|
} catch (error) {
|
|
1175
1304
|
if (fd !== void 0) {
|
|
1176
1305
|
try {
|
|
1177
|
-
|
|
1306
|
+
closeSync3(fd);
|
|
1178
1307
|
} catch {
|
|
1179
1308
|
}
|
|
1180
1309
|
}
|
|
1181
1310
|
try {
|
|
1182
|
-
|
|
1311
|
+
rmSync3(temp, { force: true });
|
|
1183
1312
|
} catch {
|
|
1184
1313
|
}
|
|
1185
1314
|
throw error;
|
|
@@ -1188,12 +1317,12 @@ function atomicJson(path, value) {
|
|
|
1188
1317
|
function quarantine(path, suffix) {
|
|
1189
1318
|
const moved = `${path}.${suffix}-${process.pid}-${randomUUID4()}`;
|
|
1190
1319
|
try {
|
|
1191
|
-
|
|
1320
|
+
renameSync4(path, moved);
|
|
1192
1321
|
} catch {
|
|
1193
1322
|
return false;
|
|
1194
1323
|
}
|
|
1195
1324
|
try {
|
|
1196
|
-
|
|
1325
|
+
rmSync3(moved, { recursive: true, force: true });
|
|
1197
1326
|
} catch {
|
|
1198
1327
|
}
|
|
1199
1328
|
return true;
|
|
@@ -1210,7 +1339,7 @@ function parseGeneration(value) {
|
|
|
1210
1339
|
}
|
|
1211
1340
|
function parseGuard(path) {
|
|
1212
1341
|
try {
|
|
1213
|
-
const value = JSON.parse(
|
|
1342
|
+
const value = JSON.parse(readFileSync4(path, "utf8"));
|
|
1214
1343
|
const generation = parseGeneration(value);
|
|
1215
1344
|
if (value.version !== 1 || !generation || typeof value.token !== "string" || !UUID_RE.test(value.token) || !validText(value.at, 128)) return null;
|
|
1216
1345
|
return { version: 1, token: value.token, at: value.at, ...generation };
|
|
@@ -1219,25 +1348,25 @@ function parseGuard(path) {
|
|
|
1219
1348
|
}
|
|
1220
1349
|
}
|
|
1221
1350
|
function acquireMutationGuard(stateDir, timeoutMs = GUARD_TIMEOUT_MS, adapter = defaultProcessPlatformAdapter) {
|
|
1222
|
-
const path =
|
|
1223
|
-
|
|
1351
|
+
const path = join6(stateDir, MUTATION_GUARD_NAME);
|
|
1352
|
+
mkdirSync4(stateDir, { recursive: true, mode: 448 });
|
|
1224
1353
|
const deadline = adapter.now() + Math.max(0, timeoutMs);
|
|
1225
1354
|
for (; ; ) {
|
|
1226
1355
|
const generation = currentProcessGeneration(adapter);
|
|
1227
1356
|
const token = randomUUID4();
|
|
1228
1357
|
let fd;
|
|
1229
1358
|
try {
|
|
1230
|
-
fd =
|
|
1359
|
+
fd = openSync3(path, "wx", 384);
|
|
1231
1360
|
const record = {
|
|
1232
1361
|
version: 1,
|
|
1233
1362
|
token,
|
|
1234
1363
|
at: new Date(adapter.now()).toISOString(),
|
|
1235
1364
|
...generation
|
|
1236
1365
|
};
|
|
1237
|
-
|
|
1366
|
+
writeFileSync3(fd, `${JSON.stringify(record)}
|
|
1238
1367
|
`, "utf8");
|
|
1239
|
-
|
|
1240
|
-
|
|
1368
|
+
fsyncSync3(fd);
|
|
1369
|
+
closeSync3(fd);
|
|
1241
1370
|
fd = void 0;
|
|
1242
1371
|
const committed = parseGuard(path);
|
|
1243
1372
|
if (!committed || committed.token !== token || committed.pid !== generation.pid || committed.processStart !== generation.processStart) continue;
|
|
@@ -1252,7 +1381,7 @@ function acquireMutationGuard(stateDir, timeoutMs = GUARD_TIMEOUT_MS, adapter =
|
|
|
1252
1381
|
} catch (error) {
|
|
1253
1382
|
if (fd !== void 0) {
|
|
1254
1383
|
try {
|
|
1255
|
-
|
|
1384
|
+
closeSync3(fd);
|
|
1256
1385
|
} catch {
|
|
1257
1386
|
}
|
|
1258
1387
|
}
|
|
@@ -1290,7 +1419,7 @@ function parseDelegates(value) {
|
|
|
1290
1419
|
}
|
|
1291
1420
|
function parseOwner(path) {
|
|
1292
1421
|
try {
|
|
1293
|
-
const value = JSON.parse(
|
|
1422
|
+
const value = JSON.parse(readFileSync4(path, "utf8"));
|
|
1294
1423
|
const generation = parseGeneration(value);
|
|
1295
1424
|
if (value.version !== 1 && value.version !== OWNER_VERSION || !generation || typeof value.token !== "string" || !UUID_RE.test(value.token) || typeof value.projectId !== "string" || !UUID_RE.test(value.projectId) || !validText(value.projectDir) || !isAbsolute(value.projectDir) || !validRole(value.role) || !validText(value.acquiredAt, 128) || !validText(value.updatedAt, 128)) return null;
|
|
1296
1425
|
const delegates = value.version === 1 ? [] : parseDelegates(value.delegates);
|
|
@@ -1313,7 +1442,7 @@ function parseOwner(path) {
|
|
|
1313
1442
|
}
|
|
1314
1443
|
}
|
|
1315
1444
|
function projectLaunchOwnerPath(stateDir) {
|
|
1316
|
-
return
|
|
1445
|
+
return join6(stateDir, OWNER_NAME);
|
|
1317
1446
|
}
|
|
1318
1447
|
function sameTarget(record, target) {
|
|
1319
1448
|
return record.projectId === target.projectId && record.projectDir === target.projectDir;
|
|
@@ -1323,13 +1452,13 @@ function sameProjectIdentity(record, target) {
|
|
|
1323
1452
|
}
|
|
1324
1453
|
function projectLaunchTokenProof(target, token) {
|
|
1325
1454
|
if (!UUID_RE.test(token)) throw new Error("invalid Frizz project launch owner token");
|
|
1326
|
-
return
|
|
1455
|
+
return createHash3("sha256").update("frizz-project-launch-v2\0").update(target.projectId).update("\0").update(target.projectDir).update("\0").update(token).digest("hex");
|
|
1327
1456
|
}
|
|
1328
1457
|
function removeStatusesForToken(stateDir, token) {
|
|
1329
1458
|
for (const name of ["dev-supervisor.lock", "server.lock"]) {
|
|
1330
|
-
const path =
|
|
1459
|
+
const path = join6(stateDir, name);
|
|
1331
1460
|
try {
|
|
1332
|
-
const value = JSON.parse(
|
|
1461
|
+
const value = JSON.parse(readFileSync4(path, "utf8"));
|
|
1333
1462
|
if (value.ownerToken === token) quarantine(path, "stale");
|
|
1334
1463
|
} catch {
|
|
1335
1464
|
}
|
|
@@ -1338,17 +1467,17 @@ function removeStatusesForToken(stateDir, token) {
|
|
|
1338
1467
|
function writeNewOwner(path, record) {
|
|
1339
1468
|
let fd;
|
|
1340
1469
|
try {
|
|
1341
|
-
fd =
|
|
1342
|
-
|
|
1470
|
+
fd = openSync3(path, "wx", 384);
|
|
1471
|
+
writeFileSync3(fd, `${JSON.stringify(record)}
|
|
1343
1472
|
`, "utf8");
|
|
1344
|
-
|
|
1345
|
-
|
|
1473
|
+
fsyncSync3(fd);
|
|
1474
|
+
closeSync3(fd);
|
|
1346
1475
|
fd = void 0;
|
|
1347
|
-
syncDirectory2(
|
|
1476
|
+
syncDirectory2(dirname3(path));
|
|
1348
1477
|
} catch (error) {
|
|
1349
1478
|
if (fd !== void 0) {
|
|
1350
1479
|
try {
|
|
1351
|
-
|
|
1480
|
+
closeSync3(fd);
|
|
1352
1481
|
} catch {
|
|
1353
1482
|
}
|
|
1354
1483
|
}
|
|
@@ -1576,7 +1705,7 @@ function writeProjectStatus(path, value) {
|
|
|
1576
1705
|
}
|
|
1577
1706
|
function removeProjectStatus(path, expected) {
|
|
1578
1707
|
try {
|
|
1579
|
-
const value = JSON.parse(
|
|
1708
|
+
const value = JSON.parse(readFileSync4(path, "utf8"));
|
|
1580
1709
|
if (value.pid !== expected.pid || value.processStart !== expected.processStart || value.publisherToken !== expected.publisherToken || value.ownerToken !== expected.ownerToken) return false;
|
|
1581
1710
|
return quarantine(path, "release");
|
|
1582
1711
|
} catch {
|
|
@@ -1640,7 +1769,7 @@ function createRetryableCleanup(run2) {
|
|
|
1640
1769
|
}
|
|
1641
1770
|
function withPhaseTimeout(name, promise, timeoutMs) {
|
|
1642
1771
|
if (timeoutMs === void 0 || !Number.isFinite(timeoutMs) || timeoutMs <= 0) return promise;
|
|
1643
|
-
return new Promise((
|
|
1772
|
+
return new Promise((resolve10, reject) => {
|
|
1644
1773
|
let settled = false;
|
|
1645
1774
|
const settle = (apply) => {
|
|
1646
1775
|
if (settled) return;
|
|
@@ -1651,18 +1780,18 @@ function withPhaseTimeout(name, promise, timeoutMs) {
|
|
|
1651
1780
|
const timer = setTimeout(() => settle(() => reject(new ShutdownPhaseTimeoutError(name, timeoutMs))), timeoutMs);
|
|
1652
1781
|
timer.unref?.();
|
|
1653
1782
|
promise.then(
|
|
1654
|
-
() => settle(
|
|
1783
|
+
() => settle(resolve10),
|
|
1655
1784
|
(error) => settle(() => reject(error))
|
|
1656
1785
|
);
|
|
1657
1786
|
});
|
|
1658
1787
|
}
|
|
1659
1788
|
function defaultDeadline(drained, timeoutMs) {
|
|
1660
|
-
return new Promise((
|
|
1789
|
+
return new Promise((resolve10, reject) => {
|
|
1661
1790
|
const timer = setTimeout(() => reject(new ShutdownTimeoutError(timeoutMs)), timeoutMs);
|
|
1662
1791
|
void drained.then(
|
|
1663
1792
|
() => {
|
|
1664
1793
|
clearTimeout(timer);
|
|
1665
|
-
|
|
1794
|
+
resolve10();
|
|
1666
1795
|
},
|
|
1667
1796
|
(error) => {
|
|
1668
1797
|
clearTimeout(timer);
|
|
@@ -1795,41 +1924,41 @@ var init_shutdown = __esm({
|
|
|
1795
1924
|
// packages/server/src/logging.ts
|
|
1796
1925
|
import {
|
|
1797
1926
|
appendFileSync,
|
|
1798
|
-
mkdirSync as
|
|
1799
|
-
openSync as
|
|
1927
|
+
mkdirSync as mkdirSync5,
|
|
1928
|
+
openSync as openSync4,
|
|
1800
1929
|
readdirSync as readdirSync2,
|
|
1801
|
-
rmSync as
|
|
1930
|
+
rmSync as rmSync4,
|
|
1802
1931
|
statSync as statSync3,
|
|
1803
1932
|
symlinkSync,
|
|
1804
|
-
writeFileSync as
|
|
1933
|
+
writeFileSync as writeFileSync4,
|
|
1805
1934
|
writeSync
|
|
1806
1935
|
} from "node:fs";
|
|
1807
|
-
import { homedir as
|
|
1808
|
-
import { join as
|
|
1809
|
-
function defaultLogRoot(stateDir, home =
|
|
1810
|
-
return stateDir ?
|
|
1936
|
+
import { homedir as homedir6 } from "node:os";
|
|
1937
|
+
import { join as join7 } from "node:path";
|
|
1938
|
+
function defaultLogRoot(stateDir, home = homedir6()) {
|
|
1939
|
+
return stateDir ? join7(stateDir, "logs") : join7(frizzPaths({ home }).state, "logs");
|
|
1811
1940
|
}
|
|
1812
1941
|
function runStamp(at) {
|
|
1813
1942
|
const pad = (value) => String(value).padStart(2, "0");
|
|
1814
1943
|
return `${at.getFullYear()}-${pad(at.getMonth() + 1)}-${pad(at.getDate())}T${pad(at.getHours())}-${pad(at.getMinutes())}-${pad(at.getSeconds())}`;
|
|
1815
1944
|
}
|
|
1816
|
-
function runLogPath(stateDir, at = /* @__PURE__ */ new Date(), pid = process.pid, home =
|
|
1945
|
+
function runLogPath(stateDir, at = /* @__PURE__ */ new Date(), pid = process.pid, home = homedir6(), env = process.env) {
|
|
1817
1946
|
const name = `frizz-${runStamp(at)}-${pid}.log`;
|
|
1818
1947
|
const override = env[LOG_PATH_ENV]?.trim();
|
|
1819
|
-
if (override) return override.endsWith(".log") ? override :
|
|
1820
|
-
return
|
|
1948
|
+
if (override) return override.endsWith(".log") ? override : join7(override, name);
|
|
1949
|
+
return join7(defaultLogRoot(stateDir, home), name);
|
|
1821
1950
|
}
|
|
1822
1951
|
function latestLogPath(dir) {
|
|
1823
|
-
return
|
|
1952
|
+
return join7(dir, "latest.log");
|
|
1824
1953
|
}
|
|
1825
1954
|
function linkLatest(dir, target) {
|
|
1826
1955
|
const link = latestLogPath(dir);
|
|
1827
1956
|
try {
|
|
1828
|
-
|
|
1957
|
+
rmSync4(link, { force: true });
|
|
1829
1958
|
symlinkSync(target, link);
|
|
1830
1959
|
} catch {
|
|
1831
1960
|
try {
|
|
1832
|
-
|
|
1961
|
+
writeFileSync4(link, `${target}
|
|
1833
1962
|
`, { mode: 384 });
|
|
1834
1963
|
} catch {
|
|
1835
1964
|
}
|
|
@@ -1844,7 +1973,7 @@ function pruneRunLogs(dir, keep = RETAINED_RUNS, days = RETAINED_DAYS, now = Dat
|
|
|
1844
1973
|
}
|
|
1845
1974
|
const dated = entries.map((name) => {
|
|
1846
1975
|
try {
|
|
1847
|
-
return { name, at: statSync3(
|
|
1976
|
+
return { name, at: statSync3(join7(dir, name)).mtimeMs };
|
|
1848
1977
|
} catch {
|
|
1849
1978
|
return { name, at: 0 };
|
|
1850
1979
|
}
|
|
@@ -1853,7 +1982,7 @@ function pruneRunLogs(dir, keep = RETAINED_RUNS, days = RETAINED_DAYS, now = Dat
|
|
|
1853
1982
|
const stale = dated.filter((entry, index) => index >= keep || entry.at < cutoff);
|
|
1854
1983
|
for (const entry of stale) {
|
|
1855
1984
|
try {
|
|
1856
|
-
|
|
1985
|
+
rmSync4(join7(dir, entry.name), { force: true });
|
|
1857
1986
|
} catch {
|
|
1858
1987
|
}
|
|
1859
1988
|
}
|
|
@@ -1867,8 +1996,8 @@ function formatDiskLine(record) {
|
|
|
1867
1996
|
}
|
|
1868
1997
|
function openLogFile(path) {
|
|
1869
1998
|
try {
|
|
1870
|
-
|
|
1871
|
-
return
|
|
1999
|
+
mkdirSync5(join7(path, ".."), { recursive: true, mode: 448 });
|
|
2000
|
+
return openSync4(path, "a", 384);
|
|
1872
2001
|
} catch {
|
|
1873
2002
|
return null;
|
|
1874
2003
|
}
|
|
@@ -1881,7 +2010,7 @@ function createLogger(options = {}) {
|
|
|
1881
2010
|
const maxBytes = options.maxBytes ?? MAX_LOG_BYTES;
|
|
1882
2011
|
let fd = path === null ? null : openLogFile(path);
|
|
1883
2012
|
if (fd !== null && path !== null && options.owner !== false) {
|
|
1884
|
-
const dir =
|
|
2013
|
+
const dir = join7(path, "..");
|
|
1885
2014
|
pruneRunLogs(dir);
|
|
1886
2015
|
linkLatest(dir, path);
|
|
1887
2016
|
}
|
|
@@ -6746,8 +6875,8 @@ function createDrainableWorker(process2, options = {}) {
|
|
|
6746
6875
|
},
|
|
6747
6876
|
drain() {
|
|
6748
6877
|
if (closed || queue.length === 0 && inFlight === 0) return Promise.resolve();
|
|
6749
|
-
return new Promise((
|
|
6750
|
-
waiters.push(
|
|
6878
|
+
return new Promise((resolve10) => {
|
|
6879
|
+
waiters.push(resolve10);
|
|
6751
6880
|
});
|
|
6752
6881
|
},
|
|
6753
6882
|
outstanding: () => queue.length + inFlight,
|
|
@@ -10723,15 +10852,15 @@ var init_settings = __esm({
|
|
|
10723
10852
|
});
|
|
10724
10853
|
|
|
10725
10854
|
// packages/server/src/discover.ts
|
|
10726
|
-
import { readdirSync as readdirSync3, statSync as statSync4, openSync as
|
|
10727
|
-
import { join as
|
|
10855
|
+
import { readdirSync as readdirSync3, statSync as statSync4, openSync as openSync5, readSync, closeSync as closeSync4 } from "node:fs";
|
|
10856
|
+
import { join as join8 } from "node:path";
|
|
10728
10857
|
function sentinelFor(sessionId) {
|
|
10729
10858
|
return `threads/${sessionId}/scratch.md`;
|
|
10730
10859
|
}
|
|
10731
10860
|
function readHead(path) {
|
|
10732
10861
|
let fd;
|
|
10733
10862
|
try {
|
|
10734
|
-
fd =
|
|
10863
|
+
fd = openSync5(path, "r");
|
|
10735
10864
|
const buf = Buffer.allocUnsafe(HEAD_BYTES);
|
|
10736
10865
|
const n = readSync(fd, buf, 0, HEAD_BYTES, 0);
|
|
10737
10866
|
return buf.toString("utf8", 0, n);
|
|
@@ -10740,7 +10869,7 @@ function readHead(path) {
|
|
|
10740
10869
|
} finally {
|
|
10741
10870
|
if (fd !== void 0) {
|
|
10742
10871
|
try {
|
|
10743
|
-
|
|
10872
|
+
closeSync4(fd);
|
|
10744
10873
|
} catch {
|
|
10745
10874
|
}
|
|
10746
10875
|
}
|
|
@@ -10761,7 +10890,7 @@ function discoverTranscriptId(logDir, sessionId, opts = {}) {
|
|
|
10761
10890
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
10762
10891
|
const id = name.slice(0, -".jsonl".length);
|
|
10763
10892
|
if (!id || id === sessionId || exclude?.has(id)) continue;
|
|
10764
|
-
const path =
|
|
10893
|
+
const path = join8(logDir, name);
|
|
10765
10894
|
let mtime;
|
|
10766
10895
|
try {
|
|
10767
10896
|
mtime = statSync4(path).mtimeMs;
|
|
@@ -10789,12 +10918,12 @@ var init_discover = __esm({
|
|
|
10789
10918
|
});
|
|
10790
10919
|
|
|
10791
10920
|
// packages/server/src/session-files.ts
|
|
10792
|
-
import { lstatSync as lstatSync2, rmSync as
|
|
10921
|
+
import { lstatSync as lstatSync2, rmSync as rmSync5 } from "node:fs";
|
|
10793
10922
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
10794
|
-
import { join as
|
|
10923
|
+
import { join as join9 } from "node:path";
|
|
10795
10924
|
function systemPromptPath(sessionId) {
|
|
10796
10925
|
if (!SESSION_ID_RE.test(sessionId)) throw new Error("invalid session id");
|
|
10797
|
-
return
|
|
10926
|
+
return join9(SYSTEM_PROMPT_DIR, `${sessionId}.md`);
|
|
10798
10927
|
}
|
|
10799
10928
|
function isDirectDirectory(path) {
|
|
10800
10929
|
try {
|
|
@@ -10814,9 +10943,9 @@ function pathAbsent(path) {
|
|
|
10814
10943
|
}
|
|
10815
10944
|
function unlinkDirectChild(parent, filename) {
|
|
10816
10945
|
if (!isDirectDirectory(parent)) return pathAbsent(parent);
|
|
10817
|
-
const child =
|
|
10946
|
+
const child = join9(parent, filename);
|
|
10818
10947
|
try {
|
|
10819
|
-
|
|
10948
|
+
rmSync5(child, { force: true });
|
|
10820
10949
|
} catch {
|
|
10821
10950
|
return false;
|
|
10822
10951
|
}
|
|
@@ -10824,14 +10953,14 @@ function unlinkDirectChild(parent, filename) {
|
|
|
10824
10953
|
}
|
|
10825
10954
|
function cleanupAdoptionSessionFiles(projectDir, sessionId) {
|
|
10826
10955
|
if (!SESSION_ID_RE.test(sessionId)) return false;
|
|
10827
|
-
const frizzDir =
|
|
10956
|
+
const frizzDir = join9(projectDir, ".frizz");
|
|
10828
10957
|
let clean = true;
|
|
10829
10958
|
if (isDirectDirectory(frizzDir)) {
|
|
10830
|
-
const threads =
|
|
10959
|
+
const threads = join9(frizzDir, "threads");
|
|
10831
10960
|
if (isDirectDirectory(threads)) {
|
|
10832
|
-
const child =
|
|
10961
|
+
const child = join9(threads, sessionId);
|
|
10833
10962
|
try {
|
|
10834
|
-
|
|
10963
|
+
rmSync5(child, { recursive: true, force: true });
|
|
10835
10964
|
} catch {
|
|
10836
10965
|
clean = false;
|
|
10837
10966
|
}
|
|
@@ -10844,7 +10973,7 @@ var SYSTEM_PROMPT_DIR, SESSION_ID_RE;
|
|
|
10844
10973
|
var init_session_files = __esm({
|
|
10845
10974
|
"packages/server/src/session-files.ts"() {
|
|
10846
10975
|
"use strict";
|
|
10847
|
-
SYSTEM_PROMPT_DIR =
|
|
10976
|
+
SYSTEM_PROMPT_DIR = join9(tmpdir2(), "frizz-sysprompts");
|
|
10848
10977
|
SESSION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{0,199}$/;
|
|
10849
10978
|
}
|
|
10850
10979
|
});
|
|
@@ -11080,10 +11209,10 @@ var init_adoption_recovery = __esm({
|
|
|
11080
11209
|
});
|
|
11081
11210
|
|
|
11082
11211
|
// packages/server/src/backend/codex-models.ts
|
|
11083
|
-
import { join as
|
|
11084
|
-
import { readFileSync as
|
|
11212
|
+
import { join as join10 } from "node:path";
|
|
11213
|
+
import { readFileSync as readFileSync5 } from "node:fs";
|
|
11085
11214
|
function cachePath(codexHome) {
|
|
11086
|
-
return
|
|
11215
|
+
return join10(codexHome, "models_cache.json");
|
|
11087
11216
|
}
|
|
11088
11217
|
function toCodexModel(raw2) {
|
|
11089
11218
|
if (!raw2 || typeof raw2 !== "object") return void 0;
|
|
@@ -11119,7 +11248,7 @@ function readCodexModels(codexHome = defaultCodexHome()) {
|
|
|
11119
11248
|
if (hit && now - hit.at < TTL_MS) return hit.models;
|
|
11120
11249
|
let models;
|
|
11121
11250
|
try {
|
|
11122
|
-
models = parseCodexModelsCache(
|
|
11251
|
+
models = parseCodexModelsCache(readFileSync5(path, "utf8"));
|
|
11123
11252
|
} catch {
|
|
11124
11253
|
models = CODEX_MODELS_FALLBACK;
|
|
11125
11254
|
}
|
|
@@ -11509,17 +11638,17 @@ var init_usage_limit = __esm({
|
|
|
11509
11638
|
});
|
|
11510
11639
|
|
|
11511
11640
|
// packages/server/src/backend/claude-broker-diagnostics.ts
|
|
11512
|
-
import { appendFileSync as appendFileSync2, mkdirSync as
|
|
11513
|
-
import { join as
|
|
11641
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync6, readFileSync as readFileSync6, renameSync as renameSync5, statSync as statSync5 } from "node:fs";
|
|
11642
|
+
import { join as join11 } from "node:path";
|
|
11514
11643
|
function claudeBrokerDiagnosticLogPath(stateDir, sessionId) {
|
|
11515
|
-
return
|
|
11644
|
+
return join11(stateDir, "claude-broker", `${sessionId}.diagnostics.log`);
|
|
11516
11645
|
}
|
|
11517
11646
|
function readClaudeBrokerExit(stateDir, sessionId) {
|
|
11518
11647
|
let newest = null;
|
|
11519
11648
|
for (const path of [`${claudeBrokerDiagnosticLogPath(stateDir, sessionId)}.1`, claudeBrokerDiagnosticLogPath(stateDir, sessionId)]) {
|
|
11520
11649
|
let text;
|
|
11521
11650
|
try {
|
|
11522
|
-
text =
|
|
11651
|
+
text = readFileSync6(path, "utf8");
|
|
11523
11652
|
} catch {
|
|
11524
11653
|
continue;
|
|
11525
11654
|
}
|
|
@@ -11554,11 +11683,11 @@ var init_claude_broker_diagnostics = __esm({
|
|
|
11554
11683
|
});
|
|
11555
11684
|
|
|
11556
11685
|
// packages/server/src/detached-daemons.ts
|
|
11557
|
-
import { existsSync as
|
|
11686
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
11558
11687
|
import { fileURLToPath } from "node:url";
|
|
11559
11688
|
function resolveDetachedDaemonEntry(moduleUrl, basename9) {
|
|
11560
11689
|
const candidates = [`./${basename9}.js`, `./${basename9}.ts`].map((rel) => fileURLToPath(new URL(rel, moduleUrl)));
|
|
11561
|
-
const found = candidates.find((path) =>
|
|
11690
|
+
const found = candidates.find((path) => existsSync4(path));
|
|
11562
11691
|
if (!found) throw new Error(`frizz is missing the ${basename9} entry \u2014 looked for ${candidates.join(" and ")}`);
|
|
11563
11692
|
return found;
|
|
11564
11693
|
}
|
|
@@ -11570,19 +11699,19 @@ var init_detached_daemons = __esm({
|
|
|
11570
11699
|
|
|
11571
11700
|
// packages/server/src/backend/claude-broker-host.ts
|
|
11572
11701
|
import { spawn } from "node:child_process";
|
|
11573
|
-
import { createHash as
|
|
11574
|
-
import { accessSync, constants as fsConstants, mkdirSync as
|
|
11575
|
-
import { delimiter, dirname as
|
|
11702
|
+
import { createHash as createHash4, randomUUID as randomUUID7 } from "node:crypto";
|
|
11703
|
+
import { accessSync, constants as fsConstants, mkdirSync as mkdirSync7, readFileSync as readFileSync7, readdirSync as readdirSync4, unlinkSync } from "node:fs";
|
|
11704
|
+
import { delimiter, dirname as dirname4, isAbsolute as isAbsolute2, join as join12 } from "node:path";
|
|
11576
11705
|
function windowsShimTarget(shimPath) {
|
|
11577
11706
|
let body;
|
|
11578
11707
|
try {
|
|
11579
|
-
body =
|
|
11708
|
+
body = readFileSync7(shimPath, "utf8");
|
|
11580
11709
|
} catch {
|
|
11581
11710
|
return void 0;
|
|
11582
11711
|
}
|
|
11583
11712
|
const target = WINDOWS_SHIM_TARGET.exec(body)?.[1];
|
|
11584
11713
|
if (!target) return void 0;
|
|
11585
|
-
const full =
|
|
11714
|
+
const full = join12(dirname4(shimPath), target);
|
|
11586
11715
|
try {
|
|
11587
11716
|
accessSync(full, fsConstants.F_OK);
|
|
11588
11717
|
return full;
|
|
@@ -11597,17 +11726,17 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
11597
11726
|
for (const dir of (env.PATH ?? "").split(delimiter)) {
|
|
11598
11727
|
if (!dir) continue;
|
|
11599
11728
|
if (windows) {
|
|
11600
|
-
const exe =
|
|
11729
|
+
const exe = join12(dir, `${candidate}.exe`);
|
|
11601
11730
|
try {
|
|
11602
11731
|
accessSync(exe, fsConstants.F_OK);
|
|
11603
11732
|
return exe;
|
|
11604
11733
|
} catch {
|
|
11605
11734
|
}
|
|
11606
|
-
const viaShim = windowsShimTarget(
|
|
11735
|
+
const viaShim = windowsShimTarget(join12(dir, `${candidate}.cmd`));
|
|
11607
11736
|
if (viaShim) return viaShim;
|
|
11608
11737
|
continue;
|
|
11609
11738
|
}
|
|
11610
|
-
const full =
|
|
11739
|
+
const full = join12(dir, candidate);
|
|
11611
11740
|
try {
|
|
11612
11741
|
accessSync(full, fsConstants.X_OK);
|
|
11613
11742
|
return full;
|
|
@@ -11617,13 +11746,13 @@ function resolveClaudeExecutableAbsolute(bin, env = process.env) {
|
|
|
11617
11746
|
throw new Error(`Claude session broker: could not resolve '${candidate}' to an absolute executable path on PATH (the SDK requires one)`);
|
|
11618
11747
|
}
|
|
11619
11748
|
function claudeBrokerSocketPath(stateDir, sessionId) {
|
|
11620
|
-
const key =
|
|
11749
|
+
const key = createHash4("sha256").update(stateDir).update("\0").update(sessionId).digest("hex").slice(0, 16);
|
|
11621
11750
|
if (process.platform === "win32") return `\\\\.\\pipe\\frizz-claude-${key}`;
|
|
11622
|
-
return
|
|
11751
|
+
return join12(process.env.TMPDIR ?? "/tmp", `frizz-claude-${key}.sock`);
|
|
11623
11752
|
}
|
|
11624
11753
|
function claudeBrokerRecordPath(stateDir, sessionId) {
|
|
11625
|
-
const key =
|
|
11626
|
-
return
|
|
11754
|
+
const key = createHash4("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
11755
|
+
return join12(stateDir, "claude-broker", `${key}.json`);
|
|
11627
11756
|
}
|
|
11628
11757
|
function pidAlive(pid) {
|
|
11629
11758
|
try {
|
|
@@ -11635,7 +11764,7 @@ function pidAlive(pid) {
|
|
|
11635
11764
|
}
|
|
11636
11765
|
function readBrokerRecord(recordPath2) {
|
|
11637
11766
|
try {
|
|
11638
|
-
return JSON.parse(
|
|
11767
|
+
return JSON.parse(readFileSync7(recordPath2, "utf8"));
|
|
11639
11768
|
} catch {
|
|
11640
11769
|
return null;
|
|
11641
11770
|
}
|
|
@@ -11652,7 +11781,7 @@ function liveBrokerRecord(recordPath2) {
|
|
|
11652
11781
|
return null;
|
|
11653
11782
|
}
|
|
11654
11783
|
function liveBrokerRecords(stateDir) {
|
|
11655
|
-
const dir =
|
|
11784
|
+
const dir = join12(stateDir, "claude-broker");
|
|
11656
11785
|
let names;
|
|
11657
11786
|
try {
|
|
11658
11787
|
names = readdirSync4(dir);
|
|
@@ -11662,7 +11791,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
11662
11791
|
const out = [];
|
|
11663
11792
|
for (const name of names) {
|
|
11664
11793
|
if (!name.endsWith(".json")) continue;
|
|
11665
|
-
const record = liveBrokerRecord(
|
|
11794
|
+
const record = liveBrokerRecord(join12(dir, name));
|
|
11666
11795
|
if (record) out.push(record);
|
|
11667
11796
|
}
|
|
11668
11797
|
return out;
|
|
@@ -11670,7 +11799,7 @@ function liveBrokerRecords(stateDir) {
|
|
|
11670
11799
|
function forkBroker(options) {
|
|
11671
11800
|
const socketPath = claudeBrokerSocketPath(options.stateDir, options.sessionId);
|
|
11672
11801
|
const recordPath2 = claudeBrokerRecordPath(options.stateDir, options.sessionId);
|
|
11673
|
-
|
|
11802
|
+
mkdirSync7(dirname4(recordPath2), { recursive: true });
|
|
11674
11803
|
const config = {
|
|
11675
11804
|
socketPath,
|
|
11676
11805
|
cwd: options.cwd,
|
|
@@ -11701,10 +11830,10 @@ function forkBroker(options) {
|
|
|
11701
11830
|
});
|
|
11702
11831
|
child.unref();
|
|
11703
11832
|
const deadline = Date.now() + (options.timeoutMs ?? 3e4);
|
|
11704
|
-
return new Promise((
|
|
11833
|
+
return new Promise((resolve10, reject) => {
|
|
11705
11834
|
const poll = () => {
|
|
11706
11835
|
const record = readBrokerRecord(recordPath2);
|
|
11707
|
-
if (record && pidAlive(record.daemonPid)) return
|
|
11836
|
+
if (record && pidAlive(record.daemonPid)) return resolve10(record);
|
|
11708
11837
|
if (Date.now() > deadline) return reject(new Error(`Claude broker for session ${options.sessionId} did not become ready`));
|
|
11709
11838
|
setTimeout(poll, 50);
|
|
11710
11839
|
};
|
|
@@ -12103,7 +12232,7 @@ var init_delivery_ledger = __esm({
|
|
|
12103
12232
|
});
|
|
12104
12233
|
|
|
12105
12234
|
// packages/server/src/codex-subagents.ts
|
|
12106
|
-
import { closeSync as
|
|
12235
|
+
import { closeSync as closeSync5, openSync as openSync6, readSync as readSync2, statSync as statSync6 } from "node:fs";
|
|
12107
12236
|
function createCodexSubAgentTracker(deps) {
|
|
12108
12237
|
const findRollouts = deps.findRollouts ?? ((ids) => findRolloutsByIds(ids, deps.codexHome));
|
|
12109
12238
|
const readAppended = deps.readAppended ?? defaultReadAppended;
|
|
@@ -12294,13 +12423,13 @@ function defaultReadAppended(path, offset) {
|
|
|
12294
12423
|
const from = restarted ? 0 : offset;
|
|
12295
12424
|
if (size <= from) return { text: "", offset: from, restarted };
|
|
12296
12425
|
try {
|
|
12297
|
-
const fd =
|
|
12426
|
+
const fd = openSync6(path, "r");
|
|
12298
12427
|
try {
|
|
12299
12428
|
const buf = Buffer.allocUnsafe(size - from);
|
|
12300
12429
|
const read = readSync2(fd, buf, 0, buf.length, from);
|
|
12301
12430
|
return { text: buf.toString("utf8", 0, read), offset: from + read, restarted };
|
|
12302
12431
|
} finally {
|
|
12303
|
-
|
|
12432
|
+
closeSync5(fd);
|
|
12304
12433
|
}
|
|
12305
12434
|
} catch {
|
|
12306
12435
|
return void 0;
|
|
@@ -12396,16 +12525,16 @@ var init_completion_relay = __esm({
|
|
|
12396
12525
|
});
|
|
12397
12526
|
|
|
12398
12527
|
// packages/server/src/tail-cache.ts
|
|
12399
|
-
import { createHash as
|
|
12400
|
-
import { closeSync as
|
|
12401
|
-
import { join as
|
|
12528
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
12529
|
+
import { closeSync as closeSync6, openSync as openSync7, readFileSync as readFileSync8, readSync as readSync3, statSync as statSync7 } from "node:fs";
|
|
12530
|
+
import { join as join13 } from "node:path";
|
|
12402
12531
|
function foldSchemaDigest(dir = import.meta.dirname) {
|
|
12403
12532
|
if (foldSchemaMemo) return foldSchemaMemo;
|
|
12404
|
-
const hash =
|
|
12533
|
+
const hash = createHash5("sha256").update("frizz-tail-state-v1\0");
|
|
12405
12534
|
let read = 0;
|
|
12406
12535
|
for (const name of FOLD_SOURCES) {
|
|
12407
12536
|
try {
|
|
12408
|
-
hash.update(name).update("\0").update(
|
|
12537
|
+
hash.update(name).update("\0").update(readFileSync8(join13(dir, name)));
|
|
12409
12538
|
read++;
|
|
12410
12539
|
} catch {
|
|
12411
12540
|
hash.update(name).update("\0missing\0");
|
|
@@ -12437,14 +12566,14 @@ function measureFence(path, offset) {
|
|
|
12437
12566
|
try {
|
|
12438
12567
|
const stat2 = statSync7(path);
|
|
12439
12568
|
if (stat2.size < offset) return null;
|
|
12440
|
-
fd =
|
|
12569
|
+
fd = openSync7(path, "r");
|
|
12441
12570
|
const window = Math.min(SAMPLE_BYTES, offset);
|
|
12442
12571
|
const head = Buffer.allocUnsafe(window);
|
|
12443
12572
|
const headRead = readSync3(fd, head, 0, window, 0);
|
|
12444
12573
|
const tail = Buffer.allocUnsafe(window);
|
|
12445
12574
|
const tailRead = readSync3(fd, tail, 0, window, offset - window);
|
|
12446
12575
|
if (headRead !== window || tailRead !== window) return null;
|
|
12447
|
-
const contentDigest =
|
|
12576
|
+
const contentDigest = createHash5("sha256").update(String(offset)).update("\0").update(head).update("\0").update(tail).digest("hex").slice(0, 32);
|
|
12448
12577
|
return {
|
|
12449
12578
|
offset,
|
|
12450
12579
|
size: stat2.size,
|
|
@@ -12457,7 +12586,7 @@ function measureFence(path, offset) {
|
|
|
12457
12586
|
} finally {
|
|
12458
12587
|
if (fd !== void 0) {
|
|
12459
12588
|
try {
|
|
12460
|
-
|
|
12589
|
+
closeSync6(fd);
|
|
12461
12590
|
} catch {
|
|
12462
12591
|
}
|
|
12463
12592
|
}
|
|
@@ -12601,9 +12730,9 @@ var init_tail_cache = __esm({
|
|
|
12601
12730
|
});
|
|
12602
12731
|
|
|
12603
12732
|
// packages/server/src/tailer.ts
|
|
12604
|
-
import { statSync as statSync8, openSync as
|
|
12605
|
-
import { join as
|
|
12606
|
-
import { homedir as
|
|
12733
|
+
import { statSync as statSync8, openSync as openSync8, readSync as readSync4, closeSync as closeSync7, readdirSync as readdirSync5, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5, readFileSync as readFileSync9, existsSync as existsSync5 } from "node:fs";
|
|
12734
|
+
import { join as join14 } from "node:path";
|
|
12735
|
+
import { homedir as homedir7, tmpdir as tmpdir3 } from "node:os";
|
|
12607
12736
|
function activityMinute(at) {
|
|
12608
12737
|
if (!at) return "";
|
|
12609
12738
|
const ms = Date.parse(at);
|
|
@@ -12865,7 +12994,7 @@ function launchTaskId(text) {
|
|
|
12865
12994
|
function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
12866
12995
|
let names;
|
|
12867
12996
|
try {
|
|
12868
|
-
names = readdirSync5(
|
|
12997
|
+
names = readdirSync5(join14(sessionDir, "subagents"));
|
|
12869
12998
|
} catch {
|
|
12870
12999
|
return [];
|
|
12871
13000
|
}
|
|
@@ -12876,7 +13005,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
12876
13005
|
if (!agentId) continue;
|
|
12877
13006
|
let parsed;
|
|
12878
13007
|
try {
|
|
12879
|
-
parsed = JSON.parse(
|
|
13008
|
+
parsed = JSON.parse(readFileSync9(join14(sessionDir, "subagents", name), "utf8"));
|
|
12880
13009
|
} catch {
|
|
12881
13010
|
continue;
|
|
12882
13011
|
}
|
|
@@ -12890,7 +13019,7 @@ function readDescendantSidecars(sessionDir, mtimeMs) {
|
|
|
12890
13019
|
agentType: text(meta.agentType),
|
|
12891
13020
|
parentAgentId: text(meta.parentAgentId),
|
|
12892
13021
|
spawnDepth: typeof meta.spawnDepth === "number" && Number.isFinite(meta.spawnDepth) ? meta.spawnDepth : void 0,
|
|
12893
|
-
spawnedAtMs: mtimeMs(
|
|
13022
|
+
spawnedAtMs: mtimeMs(join14(sessionDir, "subagents", name))
|
|
12894
13023
|
});
|
|
12895
13024
|
}
|
|
12896
13025
|
return out;
|
|
@@ -13338,13 +13467,13 @@ function defaultMtimeMs(path) {
|
|
|
13338
13467
|
}
|
|
13339
13468
|
}
|
|
13340
13469
|
function defaultLogDir(project) {
|
|
13341
|
-
return
|
|
13470
|
+
return join14(homedir7(), ".claude", "projects", project.cwdSlug);
|
|
13342
13471
|
}
|
|
13343
13472
|
function defaultReadPermMarker(project) {
|
|
13344
13473
|
if (!project.stateDir) return () => void 0;
|
|
13345
13474
|
return (slug) => {
|
|
13346
13475
|
try {
|
|
13347
|
-
const parsed = JSON.parse(
|
|
13476
|
+
const parsed = JSON.parse(readFileSync9(permMarkerPath(project, slug), "utf8"));
|
|
13348
13477
|
return isPermMarker(parsed) ? parsed : void 0;
|
|
13349
13478
|
} catch {
|
|
13350
13479
|
return void 0;
|
|
@@ -13362,7 +13491,7 @@ function defaultBrokerDaemonAlive(project, now) {
|
|
|
13362
13491
|
try {
|
|
13363
13492
|
const path = claudeBrokerRecordPath(project.stateDir, sessionId);
|
|
13364
13493
|
const record = readBrokerRecord(path);
|
|
13365
|
-
if (!record) alive =
|
|
13494
|
+
if (!record) alive = existsSync5(path);
|
|
13366
13495
|
else if (typeof record.daemonPid !== "number") alive = true;
|
|
13367
13496
|
else {
|
|
13368
13497
|
try {
|
|
@@ -13508,7 +13637,7 @@ function createTailer(deps) {
|
|
|
13508
13637
|
return "";
|
|
13509
13638
|
}
|
|
13510
13639
|
const defaultBackend = {
|
|
13511
|
-
transcriptPath: (sessionId) =>
|
|
13640
|
+
transcriptPath: (sessionId) => join14(logDir, `${sessionId}.jsonl`),
|
|
13512
13641
|
foldLine: (state, line) => {
|
|
13513
13642
|
const rec = parseLine(line);
|
|
13514
13643
|
if (rec) applyRecord(state, rec);
|
|
@@ -13629,7 +13758,7 @@ ${ask}`;
|
|
|
13629
13758
|
return state.path.replace(/\.jsonl$/, "");
|
|
13630
13759
|
}
|
|
13631
13760
|
function descendantSidecars(state) {
|
|
13632
|
-
const at = mtimeMs(
|
|
13761
|
+
const at = mtimeMs(join14(sessionDirOf(state), "subagents"));
|
|
13633
13762
|
const cached2 = descendantIndex.get(state.slug);
|
|
13634
13763
|
if (cached2 && cached2.at === at) return cached2.all;
|
|
13635
13764
|
const all = readDescendantSidecars(sessionDirOf(state), mtimeMs);
|
|
@@ -13643,7 +13772,7 @@ ${ask}`;
|
|
|
13643
13772
|
return descendantIndex.get(state.slug)?.byToolUse.get(id);
|
|
13644
13773
|
}
|
|
13645
13774
|
function descendantTranscript(state, meta) {
|
|
13646
|
-
return
|
|
13775
|
+
return join14(sessionDirOf(state), "subagents", `agent-${meta.agentId}.jsonl`);
|
|
13647
13776
|
}
|
|
13648
13777
|
function subAgentDescendantTasks(slug, id) {
|
|
13649
13778
|
const state = states.get(slug);
|
|
@@ -13902,7 +14031,7 @@ ${ask}`;
|
|
|
13902
14031
|
if (name.startsWith(".") || !name.endsWith(".jsonl")) continue;
|
|
13903
14032
|
const id = name.slice(0, -".jsonl".length);
|
|
13904
14033
|
if (!id || registered.has(id)) continue;
|
|
13905
|
-
const path =
|
|
14034
|
+
const path = join14(logDir, name);
|
|
13906
14035
|
let mtime;
|
|
13907
14036
|
try {
|
|
13908
14037
|
mtime = statSync8(path).mtimeMs;
|
|
@@ -14106,14 +14235,14 @@ ${ask}`;
|
|
|
14106
14235
|
if (size <= state.offset) return;
|
|
14107
14236
|
let chunk = "";
|
|
14108
14237
|
try {
|
|
14109
|
-
const fd =
|
|
14238
|
+
const fd = openSync8(state.path, "r");
|
|
14110
14239
|
try {
|
|
14111
14240
|
const buf = Buffer.allocUnsafe(size - state.offset);
|
|
14112
14241
|
const read = readSync4(fd, buf, 0, buf.length, state.offset);
|
|
14113
14242
|
chunk = buf.toString("utf8", 0, read);
|
|
14114
14243
|
state.offset += read;
|
|
14115
14244
|
} finally {
|
|
14116
|
-
|
|
14245
|
+
closeSync7(fd);
|
|
14117
14246
|
}
|
|
14118
14247
|
} catch {
|
|
14119
14248
|
return;
|
|
@@ -14152,8 +14281,8 @@ ${ask}`;
|
|
|
14152
14281
|
`thread ${row.slug} (session ${row.session_id}): no transcript ${DISCOVERY_GRACE_MS / 1e3}s after dispatch \u2014 likely a boot failure. ${isHeadlessRow(row) && !pane.trim() && !authFailure ? "" : "Pane:\n"}${detail.slice(0, 4e3)}`
|
|
14153
14282
|
);
|
|
14154
14283
|
try {
|
|
14155
|
-
|
|
14156
|
-
|
|
14284
|
+
mkdirSync8(STALL_LOG_DIR, { recursive: true });
|
|
14285
|
+
writeFileSync5(join14(STALL_LOG_DIR, `${row.slug}.stall.log`), `session_id: ${row.session_id}
|
|
14157
14286
|
captured_at: ${new Date(now()).toISOString()}
|
|
14158
14287
|
|
|
14159
14288
|
${detail}
|
|
@@ -14192,7 +14321,7 @@ ${detail}
|
|
|
14192
14321
|
committed = false;
|
|
14193
14322
|
}
|
|
14194
14323
|
if (!committed) return false;
|
|
14195
|
-
state.path =
|
|
14324
|
+
state.path = join14(logDir, `${found}.jsonl`);
|
|
14196
14325
|
state.offset = 0;
|
|
14197
14326
|
state.partial = "";
|
|
14198
14327
|
state.primed = false;
|
|
@@ -14220,7 +14349,7 @@ ${detail}
|
|
|
14220
14349
|
let state = states.get(row.slug);
|
|
14221
14350
|
const runtimeGeneration = row.runtime_generation ?? 0;
|
|
14222
14351
|
if (!state || state.sessionId !== row.session_id || state.nativeSessionId !== nativeId || state.runtimeGeneration !== runtimeGeneration) {
|
|
14223
|
-
const path = backend.transcriptPath(nativeId) ??
|
|
14352
|
+
const path = backend.transcriptPath(nativeId) ?? join14(logDir, `${nativeId}.jsonl`);
|
|
14224
14353
|
state = newTailState(row.slug, row.session_id, path, false, nativeId, runtimeGeneration);
|
|
14225
14354
|
state.dismissedOps = deps.storage.retiredOps(row.slug, row.session_id);
|
|
14226
14355
|
hydrateFromCache(state, row, nativeId);
|
|
@@ -14588,7 +14717,7 @@ var init_tailer = __esm({
|
|
|
14588
14717
|
CACHE_FLUSH_MS = 3e4;
|
|
14589
14718
|
PRIME_PROGRESS_EVERY = 20;
|
|
14590
14719
|
DISCOVER_RETRY_MS = 15e3;
|
|
14591
|
-
STALL_LOG_DIR =
|
|
14720
|
+
STALL_LOG_DIR = join14(tmpdir3(), "frizz-worker-logs");
|
|
14592
14721
|
PERM_YES_OPTION = /(^|\n)\s*(❯\s*)?1\.\s+Yes\b/;
|
|
14593
14722
|
PERM_QUESTION = /\b(?:Do you want|Would you like)\b/;
|
|
14594
14723
|
PERM_FOOTER = /\bEsc to (cancel|reject)\b/;
|
|
@@ -14653,14 +14782,14 @@ var init_tailer = __esm({
|
|
|
14653
14782
|
});
|
|
14654
14783
|
|
|
14655
14784
|
// packages/server/src/backend/codex.ts
|
|
14656
|
-
import { join as
|
|
14657
|
-
import { homedir as
|
|
14785
|
+
import { join as join15 } from "node:path";
|
|
14786
|
+
import { homedir as homedir8 } from "node:os";
|
|
14658
14787
|
import { readdirSync as readdirSync6, statSync as statSync9 } from "node:fs";
|
|
14659
14788
|
function defaultCodexHome() {
|
|
14660
|
-
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME :
|
|
14789
|
+
return process.env.CODEX_HOME && process.env.CODEX_HOME.trim() ? process.env.CODEX_HOME : join15(homedir8(), ".codex");
|
|
14661
14790
|
}
|
|
14662
14791
|
function sessionsDir(codexHome) {
|
|
14663
|
-
return
|
|
14792
|
+
return join15(codexHome, "sessions");
|
|
14664
14793
|
}
|
|
14665
14794
|
function codexSandbox(mode) {
|
|
14666
14795
|
switch (mode) {
|
|
@@ -15077,17 +15206,17 @@ function collectRollouts(dir, out, budget) {
|
|
|
15077
15206
|
const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).sort(descByName);
|
|
15078
15207
|
for (const d of dirs) {
|
|
15079
15208
|
if (budget.n <= 0) return;
|
|
15080
|
-
collectRollouts(
|
|
15209
|
+
collectRollouts(join15(dir, d.name), out, budget);
|
|
15081
15210
|
}
|
|
15082
15211
|
for (const f of files) {
|
|
15083
15212
|
if (budget.n <= 0) return;
|
|
15084
15213
|
let mtimeMs;
|
|
15085
15214
|
try {
|
|
15086
|
-
mtimeMs = statSync9(
|
|
15215
|
+
mtimeMs = statSync9(join15(dir, f.name)).mtimeMs;
|
|
15087
15216
|
} catch {
|
|
15088
15217
|
continue;
|
|
15089
15218
|
}
|
|
15090
|
-
out.push({ path:
|
|
15219
|
+
out.push({ path: join15(dir, f.name), mtimeMs });
|
|
15091
15220
|
budget.n--;
|
|
15092
15221
|
}
|
|
15093
15222
|
}
|
|
@@ -17508,7 +17637,7 @@ var require_extension = __commonJS({
|
|
|
17508
17637
|
if (dest[name] === void 0) dest[name] = [elem];
|
|
17509
17638
|
else dest[name].push(elem);
|
|
17510
17639
|
}
|
|
17511
|
-
function
|
|
17640
|
+
function parse2(header) {
|
|
17512
17641
|
const offers = /* @__PURE__ */ Object.create(null);
|
|
17513
17642
|
let params = /* @__PURE__ */ Object.create(null);
|
|
17514
17643
|
let mustUnescape = false;
|
|
@@ -17648,7 +17777,7 @@ var require_extension = __commonJS({
|
|
|
17648
17777
|
}).join(", ");
|
|
17649
17778
|
}).join(", ");
|
|
17650
17779
|
}
|
|
17651
|
-
module.exports = { format, parse };
|
|
17780
|
+
module.exports = { format, parse: parse2 };
|
|
17652
17781
|
}
|
|
17653
17782
|
});
|
|
17654
17783
|
|
|
@@ -17661,7 +17790,7 @@ var require_websocket = __commonJS({
|
|
|
17661
17790
|
var http = __require("http");
|
|
17662
17791
|
var net2 = __require("net");
|
|
17663
17792
|
var tls = __require("tls");
|
|
17664
|
-
var { randomBytes: randomBytes2, createHash:
|
|
17793
|
+
var { randomBytes: randomBytes2, createHash: createHash16 } = __require("crypto");
|
|
17665
17794
|
var { Duplex, Readable } = __require("stream");
|
|
17666
17795
|
var { URL: URL2 } = __require("url");
|
|
17667
17796
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -17682,7 +17811,7 @@ var require_websocket = __commonJS({
|
|
|
17682
17811
|
var {
|
|
17683
17812
|
EventTarget: { addEventListener: addEventListener2, removeEventListener }
|
|
17684
17813
|
} = require_event_target();
|
|
17685
|
-
var { format, parse } = require_extension();
|
|
17814
|
+
var { format, parse: parse2 } = require_extension();
|
|
17686
17815
|
var { toBuffer } = require_buffer_util();
|
|
17687
17816
|
var kAborted = Symbol("kAborted");
|
|
17688
17817
|
var protocolVersions = [8, 13];
|
|
@@ -18329,7 +18458,7 @@ var require_websocket = __commonJS({
|
|
|
18329
18458
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
18330
18459
|
return;
|
|
18331
18460
|
}
|
|
18332
|
-
const digest =
|
|
18461
|
+
const digest = createHash16("sha1").update(key + GUID).digest("base64");
|
|
18333
18462
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
18334
18463
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
18335
18464
|
return;
|
|
@@ -18359,7 +18488,7 @@ var require_websocket = __commonJS({
|
|
|
18359
18488
|
}
|
|
18360
18489
|
let extensions;
|
|
18361
18490
|
try {
|
|
18362
|
-
extensions =
|
|
18491
|
+
extensions = parse2(secWebSocketExtensions);
|
|
18363
18492
|
} catch (err) {
|
|
18364
18493
|
const message = "Invalid Sec-WebSocket-Extensions header";
|
|
18365
18494
|
abortHandshake(websocket, socket, message);
|
|
@@ -18651,7 +18780,7 @@ var require_subprotocol = __commonJS({
|
|
|
18651
18780
|
"node_modules/.pnpm/ws@8.21.0/node_modules/ws/lib/subprotocol.js"(exports, module) {
|
|
18652
18781
|
"use strict";
|
|
18653
18782
|
var { tokenChars } = require_validation();
|
|
18654
|
-
function
|
|
18783
|
+
function parse2(header) {
|
|
18655
18784
|
const protocols = /* @__PURE__ */ new Set();
|
|
18656
18785
|
let start = -1;
|
|
18657
18786
|
let end = -1;
|
|
@@ -18687,7 +18816,7 @@ var require_subprotocol = __commonJS({
|
|
|
18687
18816
|
protocols.add(protocol);
|
|
18688
18817
|
return protocols;
|
|
18689
18818
|
}
|
|
18690
|
-
module.exports = { parse };
|
|
18819
|
+
module.exports = { parse: parse2 };
|
|
18691
18820
|
}
|
|
18692
18821
|
});
|
|
18693
18822
|
|
|
@@ -18698,7 +18827,7 @@ var require_websocket_server = __commonJS({
|
|
|
18698
18827
|
var EventEmitter = __require("events");
|
|
18699
18828
|
var http = __require("http");
|
|
18700
18829
|
var { Duplex } = __require("stream");
|
|
18701
|
-
var { createHash:
|
|
18830
|
+
var { createHash: createHash16 } = __require("crypto");
|
|
18702
18831
|
var extension2 = require_extension();
|
|
18703
18832
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
18704
18833
|
var subprotocol2 = require_subprotocol();
|
|
@@ -19005,7 +19134,7 @@ var require_websocket_server = __commonJS({
|
|
|
19005
19134
|
);
|
|
19006
19135
|
}
|
|
19007
19136
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
19008
|
-
const digest =
|
|
19137
|
+
const digest = createHash16("sha1").update(key + GUID).digest("base64");
|
|
19009
19138
|
const headers = [
|
|
19010
19139
|
"HTTP/1.1 101 Switching Protocols",
|
|
19011
19140
|
"Upgrade: websocket",
|
|
@@ -19175,21 +19304,21 @@ var init_codex_mcp = __esm({
|
|
|
19175
19304
|
// packages/server/src/backend/codex-app-server-native.ts
|
|
19176
19305
|
import { spawn as spawn2 } from "node:child_process";
|
|
19177
19306
|
import { connect } from "node:net";
|
|
19178
|
-
import { createHash as
|
|
19179
|
-
import { existsSync as
|
|
19180
|
-
import { join as
|
|
19307
|
+
import { createHash as createHash6, randomUUID as randomUUID8 } from "node:crypto";
|
|
19308
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync9, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
19309
|
+
import { join as join16 } from "node:path";
|
|
19181
19310
|
import { PassThrough, Writable } from "node:stream";
|
|
19182
19311
|
import { StringDecoder } from "node:string_decoder";
|
|
19183
19312
|
function nativeDir(stateDir) {
|
|
19184
|
-
return
|
|
19313
|
+
return join16(stateDir, "codex-app-server-native");
|
|
19185
19314
|
}
|
|
19186
19315
|
function nativeRecordPath(stateDir, projectId) {
|
|
19187
|
-
return
|
|
19316
|
+
return join16(nativeDir(stateDir), `${projectId}.json`);
|
|
19188
19317
|
}
|
|
19189
19318
|
function nativeListenSocketPath(stateDir, projectId) {
|
|
19190
|
-
const key =
|
|
19319
|
+
const key = createHash6("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
19191
19320
|
if (process.platform === "win32") return `\\\\.\\pipe\\frizz-codex-native-${key}`;
|
|
19192
|
-
return
|
|
19321
|
+
return join16(process.env.TMPDIR ?? "/tmp", `frizz-codex-native-${key}.sock`);
|
|
19193
19322
|
}
|
|
19194
19323
|
function pidAlive2(pid) {
|
|
19195
19324
|
try {
|
|
@@ -19201,7 +19330,7 @@ function pidAlive2(pid) {
|
|
|
19201
19330
|
}
|
|
19202
19331
|
function readNativeRecord(stateDir, projectId) {
|
|
19203
19332
|
try {
|
|
19204
|
-
const value = JSON.parse(
|
|
19333
|
+
const value = JSON.parse(readFileSync10(nativeRecordPath(stateDir, projectId), "utf8"));
|
|
19205
19334
|
if (typeof value.listenerPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
19206
19335
|
return {
|
|
19207
19336
|
projectId,
|
|
@@ -19217,7 +19346,7 @@ function readNativeRecord(stateDir, projectId) {
|
|
|
19217
19346
|
function liveNativeRecord(stateDir, projectId) {
|
|
19218
19347
|
const record = readNativeRecord(stateDir, projectId);
|
|
19219
19348
|
if (!record) return null;
|
|
19220
|
-
if (pidAlive2(record.listenerPid) &&
|
|
19349
|
+
if (pidAlive2(record.listenerPid) && existsSync6(record.socketPath)) return record;
|
|
19221
19350
|
try {
|
|
19222
19351
|
unlinkSync2(nativeRecordPath(stateDir, projectId));
|
|
19223
19352
|
} catch {
|
|
@@ -19242,7 +19371,7 @@ async function stopNativeListener(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
19242
19371
|
if (!record) return;
|
|
19243
19372
|
const deadline = Date.now() + timeoutMs;
|
|
19244
19373
|
while (pidAlive2(record.listenerPid) && Date.now() < deadline) {
|
|
19245
|
-
await new Promise((
|
|
19374
|
+
await new Promise((resolve10) => setTimeout(resolve10, 25));
|
|
19246
19375
|
}
|
|
19247
19376
|
if (pidAlive2(record.listenerPid)) {
|
|
19248
19377
|
try {
|
|
@@ -19250,16 +19379,16 @@ async function stopNativeListener(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
19250
19379
|
} catch {
|
|
19251
19380
|
}
|
|
19252
19381
|
while (pidAlive2(record.listenerPid) && Date.now() < deadline + 2e3) {
|
|
19253
|
-
await new Promise((
|
|
19382
|
+
await new Promise((resolve10) => setTimeout(resolve10, 25));
|
|
19254
19383
|
}
|
|
19255
19384
|
}
|
|
19256
19385
|
}
|
|
19257
19386
|
function socketAccepting(socketPath) {
|
|
19258
|
-
return new Promise((
|
|
19387
|
+
return new Promise((resolve10) => {
|
|
19259
19388
|
const probe = connect(socketPath);
|
|
19260
19389
|
const done = (value) => {
|
|
19261
19390
|
probe.destroy();
|
|
19262
|
-
|
|
19391
|
+
resolve10(value);
|
|
19263
19392
|
};
|
|
19264
19393
|
probe.once("connect", () => done(true));
|
|
19265
19394
|
probe.once("error", () => done(false));
|
|
@@ -19267,7 +19396,7 @@ function socketAccepting(socketPath) {
|
|
|
19267
19396
|
});
|
|
19268
19397
|
}
|
|
19269
19398
|
function attach(record, timeoutMs) {
|
|
19270
|
-
return new Promise((
|
|
19399
|
+
return new Promise((resolve10, reject) => {
|
|
19271
19400
|
const socket = new import_websocket.default(`ws+unix://${record.socketPath}:/`, { perMessageDeflate: false });
|
|
19272
19401
|
const stdout = new PassThrough();
|
|
19273
19402
|
const stderr = new PassThrough();
|
|
@@ -19320,7 +19449,7 @@ function attach(record, timeoutMs) {
|
|
|
19320
19449
|
if (settled) return;
|
|
19321
19450
|
settled = true;
|
|
19322
19451
|
clearTimeout(timer);
|
|
19323
|
-
|
|
19452
|
+
resolve10(handle);
|
|
19324
19453
|
});
|
|
19325
19454
|
socket.on("message", (data) => {
|
|
19326
19455
|
const text = typeof data === "string" ? data : Buffer.isBuffer(data) ? data.toString("utf8") : Buffer.concat(data).toString("utf8");
|
|
@@ -19348,9 +19477,9 @@ function attach(record, timeoutMs) {
|
|
|
19348
19477
|
}
|
|
19349
19478
|
async function startListener(options) {
|
|
19350
19479
|
const { stateDir, projectId } = options;
|
|
19351
|
-
|
|
19480
|
+
mkdirSync9(nativeDir(stateDir), { recursive: true });
|
|
19352
19481
|
const socketPath = nativeListenSocketPath(stateDir, projectId);
|
|
19353
|
-
if (
|
|
19482
|
+
if (existsSync6(socketPath) && !await socketAccepting(socketPath)) {
|
|
19354
19483
|
try {
|
|
19355
19484
|
unlinkSync2(socketPath);
|
|
19356
19485
|
} catch {
|
|
@@ -19371,13 +19500,13 @@ async function startListener(options) {
|
|
|
19371
19500
|
socketPath,
|
|
19372
19501
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
19373
19502
|
};
|
|
19374
|
-
|
|
19503
|
+
writeFileSync6(nativeRecordPath(stateDir, projectId), JSON.stringify(record));
|
|
19375
19504
|
const deadline = Date.now() + (options.timeoutMs ?? 3e4);
|
|
19376
19505
|
for (; ; ) {
|
|
19377
|
-
if (
|
|
19506
|
+
if (existsSync6(socketPath) && await socketAccepting(socketPath)) return record;
|
|
19378
19507
|
if (!pidAlive2(record.listenerPid)) throw new Error("codex app-server listener exited before it became ready");
|
|
19379
19508
|
if (Date.now() > deadline) throw new Error("codex app-server listener did not become ready");
|
|
19380
|
-
await new Promise((
|
|
19509
|
+
await new Promise((resolve10) => setTimeout(resolve10, 50));
|
|
19381
19510
|
}
|
|
19382
19511
|
}
|
|
19383
19512
|
var PRESUMED_LOSSY_REJOIN, nativeListenCodexAppServerHost;
|
|
@@ -19438,21 +19567,21 @@ var init_codex_app_server_native = __esm({
|
|
|
19438
19567
|
// packages/server/src/backend/codex-app-server-host.ts
|
|
19439
19568
|
import { spawn as spawn3 } from "node:child_process";
|
|
19440
19569
|
import { createConnection } from "node:net";
|
|
19441
|
-
import { createHash as
|
|
19442
|
-
import { existsSync as
|
|
19443
|
-
import { join as
|
|
19570
|
+
import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
|
|
19571
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync10, readFileSync as readFileSync11, unlinkSync as unlinkSync3 } from "node:fs";
|
|
19572
|
+
import { join as join17 } from "node:path";
|
|
19444
19573
|
import { PassThrough as PassThrough2, Writable as Writable2 } from "node:stream";
|
|
19445
19574
|
import { StringDecoder as StringDecoder2 } from "node:string_decoder";
|
|
19446
19575
|
function daemonDir(stateDir) {
|
|
19447
|
-
return
|
|
19576
|
+
return join17(stateDir, "codex-app-server");
|
|
19448
19577
|
}
|
|
19449
19578
|
function recordPath(stateDir, projectId) {
|
|
19450
|
-
return
|
|
19579
|
+
return join17(daemonDir(stateDir), `${projectId}.json`);
|
|
19451
19580
|
}
|
|
19452
19581
|
function codexAppServerSocketPath(stateDir, projectId) {
|
|
19453
|
-
const key =
|
|
19582
|
+
const key = createHash7("sha256").update(stateDir).update("\0").update(projectId).digest("hex").slice(0, 16);
|
|
19454
19583
|
if (process.platform === "win32") return `\\\\.\\pipe\\frizz-codex-${key}`;
|
|
19455
|
-
return
|
|
19584
|
+
return join17(process.env.TMPDIR ?? "/tmp", `frizz-codex-${key}.sock`);
|
|
19456
19585
|
}
|
|
19457
19586
|
function pidAlive3(pid) {
|
|
19458
19587
|
try {
|
|
@@ -19464,7 +19593,7 @@ function pidAlive3(pid) {
|
|
|
19464
19593
|
}
|
|
19465
19594
|
function readDaemonRecord(stateDir, projectId) {
|
|
19466
19595
|
try {
|
|
19467
|
-
const value = JSON.parse(
|
|
19596
|
+
const value = JSON.parse(readFileSync11(recordPath(stateDir, projectId), "utf8"));
|
|
19468
19597
|
if (typeof value.daemonPid !== "number" || typeof value.socketPath !== "string" || typeof value.generation !== "string") return null;
|
|
19469
19598
|
return {
|
|
19470
19599
|
projectId,
|
|
@@ -19480,7 +19609,7 @@ function readDaemonRecord(stateDir, projectId) {
|
|
|
19480
19609
|
}
|
|
19481
19610
|
function readDaemonExitBreadcrumb(stateDir, projectId) {
|
|
19482
19611
|
try {
|
|
19483
|
-
const value = JSON.parse(
|
|
19612
|
+
const value = JSON.parse(readFileSync11(`${recordPath(stateDir, projectId)}.exit`, "utf8"));
|
|
19484
19613
|
if (typeof value.generation !== "string" || typeof value.reason !== "string") return null;
|
|
19485
19614
|
return {
|
|
19486
19615
|
generation: value.generation,
|
|
@@ -19522,7 +19651,7 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
19522
19651
|
if (!record) return;
|
|
19523
19652
|
const deadline = Date.now() + timeoutMs;
|
|
19524
19653
|
while (pidAlive3(record.daemonPid) && Date.now() < deadline) {
|
|
19525
|
-
await new Promise((
|
|
19654
|
+
await new Promise((resolve10) => setTimeout(resolve10, 25));
|
|
19526
19655
|
}
|
|
19527
19656
|
if (pidAlive3(record.daemonPid)) {
|
|
19528
19657
|
try {
|
|
@@ -19530,13 +19659,13 @@ async function stopCodexAppServerDaemon(stateDir, projectId, timeoutMs = 1e4) {
|
|
|
19530
19659
|
} catch {
|
|
19531
19660
|
}
|
|
19532
19661
|
while (pidAlive3(record.daemonPid) && Date.now() < deadline + 2e3) {
|
|
19533
|
-
await new Promise((
|
|
19662
|
+
await new Promise((resolve10) => setTimeout(resolve10, 25));
|
|
19534
19663
|
}
|
|
19535
19664
|
}
|
|
19536
19665
|
}
|
|
19537
19666
|
function forkDaemon(options) {
|
|
19538
19667
|
const { stateDir, projectId } = options;
|
|
19539
|
-
|
|
19668
|
+
mkdirSync10(daemonDir(stateDir), { recursive: true });
|
|
19540
19669
|
const record = recordPath(stateDir, projectId);
|
|
19541
19670
|
try {
|
|
19542
19671
|
unlinkSync3(record);
|
|
@@ -19572,10 +19701,10 @@ function forkDaemon(options) {
|
|
|
19572
19701
|
});
|
|
19573
19702
|
child.unref();
|
|
19574
19703
|
const deadline = Date.now() + (options.timeoutMs ?? 3e4);
|
|
19575
|
-
return new Promise((
|
|
19704
|
+
return new Promise((resolve10, reject) => {
|
|
19576
19705
|
const poll = () => {
|
|
19577
19706
|
const found = readDaemonRecord(stateDir, projectId);
|
|
19578
|
-
if (found && pidAlive3(found.daemonPid)) return
|
|
19707
|
+
if (found && pidAlive3(found.daemonPid)) return resolve10(found);
|
|
19579
19708
|
if (!pidAlive3(child.pid ?? -1) && !found) return reject(new Error("codex app-server daemon exited before it became ready"));
|
|
19580
19709
|
if (Date.now() > deadline) return reject(new Error("codex app-server daemon did not become ready"));
|
|
19581
19710
|
setTimeout(poll, 50);
|
|
@@ -19593,7 +19722,7 @@ function helloDropCount(line) {
|
|
|
19593
19722
|
}
|
|
19594
19723
|
}
|
|
19595
19724
|
function attach2(record, timeoutMs) {
|
|
19596
|
-
return new Promise((
|
|
19725
|
+
return new Promise((resolve10, reject) => {
|
|
19597
19726
|
const socket = createConnection(record.socketPath);
|
|
19598
19727
|
const stdout = new PassThrough2();
|
|
19599
19728
|
const stderr = new PassThrough2();
|
|
@@ -19643,7 +19772,7 @@ function attach2(record, timeoutMs) {
|
|
|
19643
19772
|
if (!settled) {
|
|
19644
19773
|
settled = true;
|
|
19645
19774
|
clearTimeout(timer);
|
|
19646
|
-
|
|
19775
|
+
resolve10({ process: handle, droppedWhileDetached: helloDropCount(trimmed) });
|
|
19647
19776
|
}
|
|
19648
19777
|
continue;
|
|
19649
19778
|
}
|
|
@@ -19711,7 +19840,7 @@ var init_codex_app_server_host = __esm({
|
|
|
19711
19840
|
}
|
|
19712
19841
|
if (process.platform !== "win32") {
|
|
19713
19842
|
const stale = codexAppServerSocketPath(options.stateDir, options.projectId);
|
|
19714
|
-
if (
|
|
19843
|
+
if (existsSync7(stale) && !liveDaemonRecord(options.stateDir, options.projectId)) {
|
|
19715
19844
|
try {
|
|
19716
19845
|
unlinkSync3(stale);
|
|
19717
19846
|
} catch {
|
|
@@ -19731,7 +19860,7 @@ var init_codex_app_server_host = __esm({
|
|
|
19731
19860
|
});
|
|
19732
19861
|
|
|
19733
19862
|
// packages/server/src/backend/codex-app-server.ts
|
|
19734
|
-
import { createHash as
|
|
19863
|
+
import { createHash as createHash8, randomUUID as randomUUID10 } from "node:crypto";
|
|
19735
19864
|
import { StringDecoder as StringDecoder3 } from "node:string_decoder";
|
|
19736
19865
|
function selectCodexHostKind(flagValue, platform3, hasSpawn) {
|
|
19737
19866
|
if (hasSpawn) return "direct";
|
|
@@ -19741,11 +19870,11 @@ function selectCodexHostKind(flagValue, platform3, hasSpawn) {
|
|
|
19741
19870
|
return nativeSupported ? "native" : "daemon";
|
|
19742
19871
|
}
|
|
19743
19872
|
function compareCodexVersions(a, b) {
|
|
19744
|
-
const
|
|
19873
|
+
const parse2 = (v) => {
|
|
19745
19874
|
const m = v.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
19746
19875
|
return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : [-1, -1, -1];
|
|
19747
19876
|
};
|
|
19748
|
-
const [x, y] = [
|
|
19877
|
+
const [x, y] = [parse2(a), parse2(b)];
|
|
19749
19878
|
for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] < y[i] ? -1 : 1;
|
|
19750
19879
|
return 0;
|
|
19751
19880
|
}
|
|
@@ -20078,7 +20207,7 @@ function canonicalJson2(value) {
|
|
|
20078
20207
|
return JSON.stringify(normalize2(value));
|
|
20079
20208
|
}
|
|
20080
20209
|
function logicalRequestId(method, parts) {
|
|
20081
|
-
const digest =
|
|
20210
|
+
const digest = createHash8("sha256").update(JSON.stringify([method, ...parts])).digest("hex");
|
|
20082
20211
|
return `codex-${digest}`;
|
|
20083
20212
|
}
|
|
20084
20213
|
function requestFingerprint(value) {
|
|
@@ -20088,7 +20217,7 @@ function requestFingerprint(value) {
|
|
|
20088
20217
|
delete record.startedAtMs;
|
|
20089
20218
|
delete record.autoResolutionMs;
|
|
20090
20219
|
}
|
|
20091
|
-
return
|
|
20220
|
+
return createHash8("sha256").update(canonicalJson2(normalized)).digest("hex");
|
|
20092
20221
|
}
|
|
20093
20222
|
function decision(id, semantic, label) {
|
|
20094
20223
|
return { id, semantic, label };
|
|
@@ -20556,12 +20685,12 @@ var init_codex_app_server = __esm({
|
|
|
20556
20685
|
if (this.pending.size >= MAX_OUTBOUND_REQUESTS) throw new Error("Codex app-server outbound request queue is full");
|
|
20557
20686
|
if (!Number.isSafeInteger(this.nextId)) throw new Error("Codex app-server request id space is exhausted");
|
|
20558
20687
|
const id = this.nextId++;
|
|
20559
|
-
const result = new Promise((
|
|
20688
|
+
const result = new Promise((resolve10, reject) => {
|
|
20560
20689
|
const timer = setTimeout(() => {
|
|
20561
20690
|
this.pending.delete(id);
|
|
20562
20691
|
reject(new Error(`Codex app-server request timed out: ${method}`));
|
|
20563
20692
|
}, this.timeoutMs);
|
|
20564
|
-
this.pending.set(id, { resolve:
|
|
20693
|
+
this.pending.set(id, { resolve: resolve10, reject, timer });
|
|
20565
20694
|
});
|
|
20566
20695
|
try {
|
|
20567
20696
|
await this.write({ id, method, params });
|
|
@@ -20598,7 +20727,7 @@ var init_codex_app_server = __esm({
|
|
|
20598
20727
|
}
|
|
20599
20728
|
whenIdle() {
|
|
20600
20729
|
if (!this.draining) return Promise.resolve();
|
|
20601
|
-
return new Promise((
|
|
20730
|
+
return new Promise((resolve10) => this.idleWaiters.add(resolve10));
|
|
20602
20731
|
}
|
|
20603
20732
|
consume(chunk) {
|
|
20604
20733
|
if (this.closed) return;
|
|
@@ -20657,7 +20786,7 @@ var init_codex_app_server = __esm({
|
|
|
20657
20786
|
queueMicrotask(() => void this.drain());
|
|
20658
20787
|
}
|
|
20659
20788
|
if (!this.draining) {
|
|
20660
|
-
for (const
|
|
20789
|
+
for (const resolve10 of this.idleWaiters) resolve10();
|
|
20661
20790
|
this.idleWaiters.clear();
|
|
20662
20791
|
}
|
|
20663
20792
|
}
|
|
@@ -20721,8 +20850,8 @@ var init_codex_app_server = __esm({
|
|
|
20721
20850
|
if (Buffer.byteLength(line, "utf8") > MAX_JSONL_BYTES) {
|
|
20722
20851
|
return Promise.reject(new Error("Codex app-server outbound message exceeded its limit"));
|
|
20723
20852
|
}
|
|
20724
|
-
return new Promise((
|
|
20725
|
-
this.child.stdin.write(line, "utf8", (error) => error ? reject(error) :
|
|
20853
|
+
return new Promise((resolve10, reject) => {
|
|
20854
|
+
this.child.stdin.write(line, "utf8", (error) => error ? reject(error) : resolve10());
|
|
20726
20855
|
});
|
|
20727
20856
|
}
|
|
20728
20857
|
fail(reason, error) {
|
|
@@ -21303,7 +21432,7 @@ var init_codex_app_server = __esm({
|
|
|
21303
21432
|
while (Date.now() - start < ms) {
|
|
21304
21433
|
const row = this.bindingForScope(threadSlug, sessionId);
|
|
21305
21434
|
if (!row || row.current_turn_id !== turnId) return;
|
|
21306
|
-
await new Promise((
|
|
21435
|
+
await new Promise((resolve10) => setTimeout(resolve10, 50));
|
|
21307
21436
|
}
|
|
21308
21437
|
}
|
|
21309
21438
|
async waitForTurnCleared(threadSlug, sessionId, ms) {
|
|
@@ -21311,7 +21440,7 @@ var init_codex_app_server = __esm({
|
|
|
21311
21440
|
while (Date.now() - start < ms) {
|
|
21312
21441
|
const row = this.bindingForScope(threadSlug, sessionId);
|
|
21313
21442
|
if (!row || row.current_turn_id === null) return;
|
|
21314
|
-
await new Promise((
|
|
21443
|
+
await new Promise((resolve10) => setTimeout(resolve10, 100));
|
|
21315
21444
|
}
|
|
21316
21445
|
}
|
|
21317
21446
|
// Dispatch entry: create a PERSISTED (ephemeral:false, restart-resumable) session with the worker
|
|
@@ -21515,14 +21644,14 @@ var init_codex_app_server = __esm({
|
|
|
21515
21644
|
released = true;
|
|
21516
21645
|
this.activeOperations--;
|
|
21517
21646
|
if (this.activeOperations === 0) {
|
|
21518
|
-
for (const
|
|
21647
|
+
for (const resolve10 of this.operationWaiters) resolve10();
|
|
21519
21648
|
this.operationWaiters.clear();
|
|
21520
21649
|
}
|
|
21521
21650
|
};
|
|
21522
21651
|
}
|
|
21523
21652
|
whenOperationsIdle() {
|
|
21524
21653
|
if (this.activeOperations === 0) return Promise.resolve();
|
|
21525
|
-
return new Promise((
|
|
21654
|
+
return new Promise((resolve10) => this.operationWaiters.add(resolve10));
|
|
21526
21655
|
}
|
|
21527
21656
|
closeDatabase() {
|
|
21528
21657
|
if (this.dbClosed) return;
|
|
@@ -22036,18 +22165,18 @@ var init_codex_app_server = __esm({
|
|
|
22036
22165
|
if (set.size === 0) this.settingsWaiters.delete(threadId);
|
|
22037
22166
|
}
|
|
22038
22167
|
};
|
|
22039
|
-
const promise = new Promise((
|
|
22040
|
-
settle =
|
|
22168
|
+
const promise = new Promise((resolve10) => {
|
|
22169
|
+
settle = resolve10;
|
|
22041
22170
|
listener = (observed) => {
|
|
22042
22171
|
detach();
|
|
22043
|
-
|
|
22172
|
+
resolve10(observed);
|
|
22044
22173
|
};
|
|
22045
22174
|
const set = this.settingsWaiters.get(threadId) ?? /* @__PURE__ */ new Set();
|
|
22046
22175
|
set.add(listener);
|
|
22047
22176
|
this.settingsWaiters.set(threadId, set);
|
|
22048
22177
|
timer = setTimeout(() => {
|
|
22049
22178
|
detach();
|
|
22050
|
-
|
|
22179
|
+
resolve10(void 0);
|
|
22051
22180
|
}, timeoutMs);
|
|
22052
22181
|
timer.unref?.();
|
|
22053
22182
|
});
|
|
@@ -22620,11 +22749,11 @@ var init_codex_app_server = __esm({
|
|
|
22620
22749
|
});
|
|
22621
22750
|
|
|
22622
22751
|
// packages/server/src/backend/codex-quota.ts
|
|
22623
|
-
import { join as
|
|
22624
|
-
import { readdirSync as readdirSync7, statSync as statSync10, openSync as
|
|
22752
|
+
import { join as join18 } from "node:path";
|
|
22753
|
+
import { readdirSync as readdirSync7, statSync as statSync10, openSync as openSync9, readSync as readSync5, fstatSync, closeSync as closeSync8 } from "node:fs";
|
|
22625
22754
|
import { spawn as spawn4 } from "node:child_process";
|
|
22626
22755
|
function sessionsDir2(codexHome) {
|
|
22627
|
-
return
|
|
22756
|
+
return join18(codexHome, "sessions");
|
|
22628
22757
|
}
|
|
22629
22758
|
function newestRollouts(dir, out, budget) {
|
|
22630
22759
|
if (budget.n <= 0) return;
|
|
@@ -22638,18 +22767,18 @@ function newestRollouts(dir, out, budget) {
|
|
|
22638
22767
|
const files = entries.filter((e) => e.isFile() && e.name.startsWith("rollout-") && e.name.endsWith(".jsonl")).map((e) => e.name).sort(descByName2);
|
|
22639
22768
|
for (const d of dirs) {
|
|
22640
22769
|
if (budget.n <= 0) return;
|
|
22641
|
-
newestRollouts(
|
|
22770
|
+
newestRollouts(join18(dir, d), out, budget);
|
|
22642
22771
|
}
|
|
22643
22772
|
for (const f of files) {
|
|
22644
22773
|
if (budget.n <= 0) return;
|
|
22645
|
-
out.push(
|
|
22774
|
+
out.push(join18(dir, f));
|
|
22646
22775
|
budget.n--;
|
|
22647
22776
|
}
|
|
22648
22777
|
}
|
|
22649
22778
|
function readTail(path) {
|
|
22650
22779
|
let fd;
|
|
22651
22780
|
try {
|
|
22652
|
-
fd =
|
|
22781
|
+
fd = openSync9(path, "r");
|
|
22653
22782
|
const size = fstatSync(fd).size;
|
|
22654
22783
|
const start = Math.max(0, size - TAIL_BYTES);
|
|
22655
22784
|
const len = size - start;
|
|
@@ -22666,7 +22795,7 @@ function readTail(path) {
|
|
|
22666
22795
|
} finally {
|
|
22667
22796
|
if (fd !== void 0) {
|
|
22668
22797
|
try {
|
|
22669
|
-
|
|
22798
|
+
closeSync8(fd);
|
|
22670
22799
|
} catch {
|
|
22671
22800
|
}
|
|
22672
22801
|
}
|
|
@@ -22747,7 +22876,7 @@ function parseCodexQuotaFromRateLimits(result) {
|
|
|
22747
22876
|
return { status: "ok", planType, windows };
|
|
22748
22877
|
}
|
|
22749
22878
|
function queryCodexRateLimits(codexHome = defaultCodexHome(), codexBin = "codex", timeoutMs = 12e3) {
|
|
22750
|
-
return new Promise((
|
|
22879
|
+
return new Promise((resolve10) => {
|
|
22751
22880
|
let child;
|
|
22752
22881
|
try {
|
|
22753
22882
|
child = spawn4(codexBin, ["app-server"], {
|
|
@@ -22755,7 +22884,7 @@ function queryCodexRateLimits(codexHome = defaultCodexHome(), codexBin = "codex"
|
|
|
22755
22884
|
env: { ...process.env, CODEX_HOME: codexHome }
|
|
22756
22885
|
});
|
|
22757
22886
|
} catch {
|
|
22758
|
-
|
|
22887
|
+
resolve10(void 0);
|
|
22759
22888
|
return;
|
|
22760
22889
|
}
|
|
22761
22890
|
let settled = false;
|
|
@@ -22767,7 +22896,7 @@ function queryCodexRateLimits(codexHome = defaultCodexHome(), codexBin = "codex"
|
|
|
22767
22896
|
child.kill("SIGKILL");
|
|
22768
22897
|
} catch {
|
|
22769
22898
|
}
|
|
22770
|
-
|
|
22899
|
+
resolve10(quota);
|
|
22771
22900
|
};
|
|
22772
22901
|
const timer = setTimeout(() => finish(void 0), timeoutMs);
|
|
22773
22902
|
const send = (msg) => {
|
|
@@ -22842,15 +22971,15 @@ var init_codex_quota = __esm({
|
|
|
22842
22971
|
});
|
|
22843
22972
|
|
|
22844
22973
|
// packages/server/src/backend/claude-quota.ts
|
|
22845
|
-
import { join as
|
|
22846
|
-
import { homedir as
|
|
22847
|
-
import { createHash as
|
|
22974
|
+
import { join as join19 } from "node:path";
|
|
22975
|
+
import { homedir as homedir9, platform } from "node:os";
|
|
22976
|
+
import { createHash as createHash9 } from "node:crypto";
|
|
22848
22977
|
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
22849
22978
|
import { execFile } from "node:child_process";
|
|
22850
22979
|
import { promisify } from "node:util";
|
|
22851
22980
|
function claudeConfigDir() {
|
|
22852
22981
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
22853
|
-
return override && override.trim() ? override :
|
|
22982
|
+
return override && override.trim() ? override : join19(homedir9(), ".claude");
|
|
22854
22983
|
}
|
|
22855
22984
|
function tokenFromCredentialsJson(raw2) {
|
|
22856
22985
|
let doc;
|
|
@@ -22879,7 +23008,7 @@ async function readKeychainToken() {
|
|
|
22879
23008
|
}
|
|
22880
23009
|
async function readAccessToken(configDir) {
|
|
22881
23010
|
try {
|
|
22882
|
-
const fromFile = tokenFromCredentialsJson(await readFile(
|
|
23011
|
+
const fromFile = tokenFromCredentialsJson(await readFile(join19(configDir, ".credentials.json"), "utf8"));
|
|
22883
23012
|
if (fromFile) return fromFile;
|
|
22884
23013
|
} catch {
|
|
22885
23014
|
}
|
|
@@ -22946,10 +23075,10 @@ function parseClaudeUsage(body, planType) {
|
|
|
22946
23075
|
return { status: "ok", planType, windows };
|
|
22947
23076
|
}
|
|
22948
23077
|
function cachePaths(cacheDir, configDir) {
|
|
22949
|
-
const profile =
|
|
23078
|
+
const profile = createHash9("sha256").update(configDir).digest("hex").slice(0, 12);
|
|
22950
23079
|
return {
|
|
22951
|
-
data:
|
|
22952
|
-
lock:
|
|
23080
|
+
data: join19(cacheDir, `claude-${profile}.json`),
|
|
23081
|
+
lock: join19(cacheDir, `claude-${profile}.lock`)
|
|
22953
23082
|
};
|
|
22954
23083
|
}
|
|
22955
23084
|
async function readShared(path) {
|
|
@@ -22972,7 +23101,7 @@ async function writeShared(path, value) {
|
|
|
22972
23101
|
}
|
|
22973
23102
|
}
|
|
22974
23103
|
function delay(ms) {
|
|
22975
|
-
return new Promise((
|
|
23104
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
22976
23105
|
}
|
|
22977
23106
|
async function acquireLock(path) {
|
|
22978
23107
|
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
@@ -23141,7 +23270,7 @@ function refreshSharedInBackground(paths, claudeBin, deps, now) {
|
|
|
23141
23270
|
async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
23142
23271
|
const now = (deps.now ?? Date.now)();
|
|
23143
23272
|
const configDir = claudeConfigDir();
|
|
23144
|
-
const cacheDir = deps.cacheDir ??
|
|
23273
|
+
const cacheDir = deps.cacheDir ?? join19(frizzRoots().cache, "quota-cache");
|
|
23145
23274
|
try {
|
|
23146
23275
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
23147
23276
|
} catch {
|
|
@@ -23152,7 +23281,7 @@ async function refreshClaudeQuotaInBackground(claudeBin = "claude", deps = {}) {
|
|
|
23152
23281
|
async function readClaudeQuota(claudeBin = "claude", deps = {}, options = {}) {
|
|
23153
23282
|
const now = (deps.now ?? Date.now)();
|
|
23154
23283
|
const configDir = claudeConfigDir();
|
|
23155
|
-
const cacheDir = deps.cacheDir ??
|
|
23284
|
+
const cacheDir = deps.cacheDir ?? join19(frizzRoots().cache, "quota-cache");
|
|
23156
23285
|
const paths = cachePaths(cacheDir, configDir);
|
|
23157
23286
|
try {
|
|
23158
23287
|
await mkdir(cacheDir, { recursive: true, mode: 448 });
|
|
@@ -23311,20 +23440,20 @@ var init_quota = __esm({
|
|
|
23311
23440
|
// packages/server/src/frizz.ts
|
|
23312
23441
|
import { execFile as execFile2 } from "node:child_process";
|
|
23313
23442
|
import { lstatSync as lstatSync3, realpathSync as realpathSync4 } from "node:fs";
|
|
23314
|
-
import { basename as basename3, dirname as
|
|
23443
|
+
import { basename as basename3, dirname as dirname5, join as join20, resolve as resolve5 } from "node:path";
|
|
23315
23444
|
import { promisify as promisify2 } from "node:util";
|
|
23316
23445
|
function frizzScriptsDir() {
|
|
23317
23446
|
if (process.env.FRIZZ_SCRIPTS_DIR) return process.env.FRIZZ_SCRIPTS_DIR;
|
|
23318
|
-
return
|
|
23447
|
+
return resolve5(import.meta.dirname, "..", "..", "..", "board");
|
|
23319
23448
|
}
|
|
23320
23449
|
function directFrizzRoot(projectDir) {
|
|
23321
23450
|
try {
|
|
23322
23451
|
const projectRoot = realpathSync4(projectDir);
|
|
23323
|
-
const path =
|
|
23452
|
+
const path = join20(projectRoot, ".frizz");
|
|
23324
23453
|
const stat2 = lstatSync3(path);
|
|
23325
23454
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
23326
23455
|
const real = realpathSync4(path);
|
|
23327
|
-
return
|
|
23456
|
+
return dirname5(real) === projectRoot && basename3(real) === ".frizz" ? real : null;
|
|
23328
23457
|
} catch {
|
|
23329
23458
|
return null;
|
|
23330
23459
|
}
|
|
@@ -23334,7 +23463,7 @@ function frizzDirExists(projectDir) {
|
|
|
23334
23463
|
}
|
|
23335
23464
|
async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
23336
23465
|
if (!directFrizzRoot(projectDir)) throw new Error("unsafe or missing .frizz directory");
|
|
23337
|
-
const { stdout } = await execFileP("node", [
|
|
23466
|
+
const { stdout } = await execFileP("node", [join20(scriptsDir, "index.mjs"), "--json"], {
|
|
23338
23467
|
cwd: projectDir,
|
|
23339
23468
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir },
|
|
23340
23469
|
maxBuffer: 32 * 1024 * 1024
|
|
@@ -23359,7 +23488,7 @@ async function readBoard(projectDir, scriptsDir = frizzScriptsDir()) {
|
|
|
23359
23488
|
};
|
|
23360
23489
|
}
|
|
23361
23490
|
async function runThreadUpdate(projectDir, slug, args, scriptsDir = frizzScriptsDir()) {
|
|
23362
|
-
await execFileP("node", [
|
|
23491
|
+
await execFileP("node", [join20(scriptsDir, "thread-update.mjs"), slug, ...args], {
|
|
23363
23492
|
cwd: projectDir,
|
|
23364
23493
|
env: { ...process.env, CLAUDE_PROJECT_DIR: projectDir }
|
|
23365
23494
|
});
|
|
@@ -24202,7 +24331,7 @@ function connectClaudeBroker(socketPath, handlers, options = {}) {
|
|
|
24202
24331
|
sendInput: (message) => send({ t: "input", message }),
|
|
24203
24332
|
answerPermission: (requestId, decision2) => send({ t: "permission", requestId, decision: decision2 }),
|
|
24204
24333
|
interrupt: () => send({ t: "interrupt" }),
|
|
24205
|
-
cancelInput: (id) => new Promise((
|
|
24334
|
+
cancelInput: (id) => new Promise((resolve10, reject) => {
|
|
24206
24335
|
if (closed) {
|
|
24207
24336
|
reject(new Error("the broker connection is closed"));
|
|
24208
24337
|
return;
|
|
@@ -24213,10 +24342,10 @@ function connectClaudeBroker(socketPath, handlers, options = {}) {
|
|
|
24213
24342
|
reject(new Error("the Claude session did not answer the unqueue request"));
|
|
24214
24343
|
}, cancelTimeoutMs);
|
|
24215
24344
|
if (timer.unref) timer.unref();
|
|
24216
|
-
pendingCancels.set(requestId, { settle:
|
|
24345
|
+
pendingCancels.set(requestId, { settle: resolve10, fail: reject, timer });
|
|
24217
24346
|
send({ t: "cancel-input", requestId, id });
|
|
24218
24347
|
}),
|
|
24219
|
-
stopTask: (taskId) => new Promise((
|
|
24348
|
+
stopTask: (taskId) => new Promise((resolve10, reject) => {
|
|
24220
24349
|
if (closed) {
|
|
24221
24350
|
reject(new Error("the broker connection is closed"));
|
|
24222
24351
|
return;
|
|
@@ -24227,12 +24356,12 @@ function connectClaudeBroker(socketPath, handlers, options = {}) {
|
|
|
24227
24356
|
reject(new Error("the Claude session did not answer the stop request"));
|
|
24228
24357
|
}, cancelTimeoutMs);
|
|
24229
24358
|
if (timer.unref) timer.unref();
|
|
24230
|
-
pendingStops.set(requestId, { settle:
|
|
24359
|
+
pendingStops.set(requestId, { settle: resolve10, fail: reject, timer });
|
|
24231
24360
|
send({ t: "stop-task", requestId, taskId });
|
|
24232
24361
|
}),
|
|
24233
24362
|
// A reload re-scans the plugin closure and can re-handshake MCP servers, so it gets a longer
|
|
24234
24363
|
// deadline than an unqueue/stop — those are answered by bookkeeping the CLI already holds.
|
|
24235
|
-
reloadPlugins: () => new Promise((
|
|
24364
|
+
reloadPlugins: () => new Promise((resolve10, reject) => {
|
|
24236
24365
|
if (closed) {
|
|
24237
24366
|
reject(new Error("the broker connection is closed"));
|
|
24238
24367
|
return;
|
|
@@ -24243,11 +24372,11 @@ function connectClaudeBroker(socketPath, handlers, options = {}) {
|
|
|
24243
24372
|
reject(new Error("the Claude session did not answer the plugin reload"));
|
|
24244
24373
|
}, reloadTimeoutMs);
|
|
24245
24374
|
if (timer.unref) timer.unref();
|
|
24246
|
-
pendingReloads.set(requestId, { settle:
|
|
24375
|
+
pendingReloads.set(requestId, { settle: resolve10, fail: reject, timer });
|
|
24247
24376
|
send({ t: "reload-plugins", requestId });
|
|
24248
24377
|
}),
|
|
24249
24378
|
// Shares the reload deadline: a re-title is a provider round trip, not local bookkeeping.
|
|
24250
|
-
renameSession: (description) => new Promise((
|
|
24379
|
+
renameSession: (description) => new Promise((resolve10, reject) => {
|
|
24251
24380
|
if (closed) {
|
|
24252
24381
|
reject(new Error("the broker connection is closed"));
|
|
24253
24382
|
return;
|
|
@@ -24258,7 +24387,7 @@ function connectClaudeBroker(socketPath, handlers, options = {}) {
|
|
|
24258
24387
|
reject(new Error("the Claude session did not answer the rename request"));
|
|
24259
24388
|
}, reloadTimeoutMs);
|
|
24260
24389
|
if (timer.unref) timer.unref();
|
|
24261
|
-
pendingRenames.set(requestId, { settle:
|
|
24390
|
+
pendingRenames.set(requestId, { settle: resolve10, fail: reject, timer });
|
|
24262
24391
|
send({ t: "rename", requestId, description });
|
|
24263
24392
|
}),
|
|
24264
24393
|
setPermissionMode: (mode) => send({ t: "set-mode", mode }),
|
|
@@ -24449,12 +24578,12 @@ var init_claude_agent_sdk_protocol = __esm({
|
|
|
24449
24578
|
});
|
|
24450
24579
|
|
|
24451
24580
|
// packages/server/src/backend/claude-permission-interactions.ts
|
|
24452
|
-
import { homedir as
|
|
24581
|
+
import { homedir as homedir10 } from "node:os";
|
|
24453
24582
|
function clip(text, max) {
|
|
24454
24583
|
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
|
24455
24584
|
}
|
|
24456
24585
|
function tildePath(path) {
|
|
24457
|
-
const home =
|
|
24586
|
+
const home = homedir10();
|
|
24458
24587
|
if (!path.startsWith(home)) return path;
|
|
24459
24588
|
const rest = path.slice(home.length);
|
|
24460
24589
|
return rest === "" ? "~" : rest.startsWith("/") ? `~${rest}` : path;
|
|
@@ -25060,19 +25189,19 @@ var init_claude_agent_broker_bridge = __esm({
|
|
|
25060
25189
|
});
|
|
25061
25190
|
|
|
25062
25191
|
// packages/server/src/backend/auth-status.ts
|
|
25063
|
-
import { join as
|
|
25064
|
-
import { homedir as
|
|
25065
|
-
import { readFileSync as
|
|
25192
|
+
import { join as join21 } from "node:path";
|
|
25193
|
+
import { homedir as homedir11, platform as platform2 } from "node:os";
|
|
25194
|
+
import { readFileSync as readFileSync12, statSync as statSync11 } from "node:fs";
|
|
25066
25195
|
import { execFile as execFile3 } from "node:child_process";
|
|
25067
25196
|
import { promisify as promisify3 } from "node:util";
|
|
25068
25197
|
function claudeConfigDir2() {
|
|
25069
25198
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
25070
|
-
return override && override.trim() ? override :
|
|
25199
|
+
return override && override.trim() ? override : join21(homedir11(), ".claude");
|
|
25071
25200
|
}
|
|
25072
25201
|
function claudeFileState(configDir) {
|
|
25073
25202
|
let raw2;
|
|
25074
25203
|
try {
|
|
25075
|
-
raw2 =
|
|
25204
|
+
raw2 = readFileSync12(join21(configDir, ".credentials.json"), "utf8");
|
|
25076
25205
|
} catch (err) {
|
|
25077
25206
|
return err.code === "ENOENT" ? "absent" : "error";
|
|
25078
25207
|
}
|
|
@@ -25105,7 +25234,7 @@ function readCodexAuthState(codexHome = defaultCodexHome()) {
|
|
|
25105
25234
|
if (process.env.OPENAI_API_KEY || process.env.CODEX_API_KEY || process.env.CODEX_ACCESS_TOKEN) return "authed";
|
|
25106
25235
|
let raw2;
|
|
25107
25236
|
try {
|
|
25108
|
-
raw2 =
|
|
25237
|
+
raw2 = readFileSync12(join21(codexHome, "auth.json"), "utf8");
|
|
25109
25238
|
} catch (err) {
|
|
25110
25239
|
return err.code === "ENOENT" ? "signed-out" : "unknown";
|
|
25111
25240
|
}
|
|
@@ -25170,7 +25299,7 @@ function asEmail(value) {
|
|
|
25170
25299
|
}
|
|
25171
25300
|
function claudeAccountFile() {
|
|
25172
25301
|
const override = process.env.CLAUDE_CONFIG_DIR;
|
|
25173
|
-
return override && override.trim() ?
|
|
25302
|
+
return override && override.trim() ? join21(override, ".claude.json") : join21(homedir11(), ".claude.json");
|
|
25174
25303
|
}
|
|
25175
25304
|
function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
25176
25305
|
let stat2;
|
|
@@ -25183,7 +25312,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
|
25183
25312
|
if (memo3 && memo3.path === path && memo3.mtimeMs === stat2.mtimeMs && memo3.size === stat2.size) return memo3.email;
|
|
25184
25313
|
let email;
|
|
25185
25314
|
try {
|
|
25186
|
-
const doc = JSON.parse(
|
|
25315
|
+
const doc = JSON.parse(readFileSync12(path, "utf8"));
|
|
25187
25316
|
email = asEmail(doc?.oauthAccount?.emailAddress);
|
|
25188
25317
|
} catch {
|
|
25189
25318
|
email = void 0;
|
|
@@ -25194,7 +25323,7 @@ function readClaudeAccountEmail(path = claudeAccountFile()) {
|
|
|
25194
25323
|
function readCodexAccountEmail(codexHome = defaultCodexHome()) {
|
|
25195
25324
|
let doc;
|
|
25196
25325
|
try {
|
|
25197
|
-
doc = JSON.parse(
|
|
25326
|
+
doc = JSON.parse(readFileSync12(join21(codexHome, "auth.json"), "utf8"));
|
|
25198
25327
|
} catch {
|
|
25199
25328
|
return void 0;
|
|
25200
25329
|
}
|
|
@@ -25261,10 +25390,10 @@ var init_auth_status = __esm({
|
|
|
25261
25390
|
});
|
|
25262
25391
|
|
|
25263
25392
|
// packages/server/src/dispatch.ts
|
|
25264
|
-
import { closeSync as
|
|
25265
|
-
import { basename as basename4, join as
|
|
25393
|
+
import { closeSync as closeSync9, constants, existsSync as existsSync8, fstatSync as fstatSync2, lstatSync as lstatSync4, openSync as openSync10, readFileSync as readFileSync13, realpathSync as realpathSync5, statSync as statSync12, writeFileSync as writeFileSync7, renameSync as renameSync6, mkdirSync as mkdirSync11, rmSync as rmSync6 } from "node:fs";
|
|
25394
|
+
import { basename as basename4, join as join22, dirname as dirname6 } from "node:path";
|
|
25266
25395
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
25267
|
-
import { createHash as
|
|
25396
|
+
import { createHash as createHash10, randomUUID as randomUUID12 } from "node:crypto";
|
|
25268
25397
|
function fallbackTitle(prompt) {
|
|
25269
25398
|
const firstLine = prompt.trim().split("\n", 1)[0].trim();
|
|
25270
25399
|
let allWords = firstLine.split(/\s+/).filter(Boolean);
|
|
@@ -25282,7 +25411,7 @@ function fallbackTitle(prompt) {
|
|
|
25282
25411
|
}
|
|
25283
25412
|
function resolveSlug(frizzDir, base, taken) {
|
|
25284
25413
|
base = ThreadSlug.parse(base);
|
|
25285
|
-
const isTaken = (slug) =>
|
|
25414
|
+
const isTaken = (slug) => existsSync8(join22(frizzDir, `${slug}.md`)) || (taken?.(slug) ?? false);
|
|
25286
25415
|
if (!isTaken(base)) return base;
|
|
25287
25416
|
for (let n = 2; ; n++) {
|
|
25288
25417
|
const suffix = `-${n}`;
|
|
@@ -25299,26 +25428,26 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
25299
25428
|
if (!parsed.success) return null;
|
|
25300
25429
|
try {
|
|
25301
25430
|
const projectRoot = realpathSync5(projectDir);
|
|
25302
|
-
const frizzPath =
|
|
25431
|
+
const frizzPath = join22(projectRoot, ".frizz");
|
|
25303
25432
|
const frizzStat = lstatSync4(frizzPath);
|
|
25304
25433
|
if (!frizzStat.isDirectory() || frizzStat.isSymbolicLink()) return null;
|
|
25305
25434
|
const realFrizz = realpathSync5(frizzPath);
|
|
25306
|
-
if (
|
|
25307
|
-
const path =
|
|
25435
|
+
if (dirname6(realFrizz) !== projectRoot || basename4(realFrizz) !== ".frizz") return null;
|
|
25436
|
+
const path = join22(realFrizz, `${parsed.data}.md`);
|
|
25308
25437
|
const before = lstatSync4(path);
|
|
25309
25438
|
if (!before.isFile() || before.isSymbolicLink()) return null;
|
|
25310
25439
|
const realPath = realpathSync5(path);
|
|
25311
|
-
if (
|
|
25440
|
+
if (dirname6(realPath) !== realFrizz || basename4(realPath) !== `${parsed.data}.md`) return null;
|
|
25312
25441
|
let contents;
|
|
25313
25442
|
let openedBefore;
|
|
25314
25443
|
let openedAfter;
|
|
25315
|
-
const fd =
|
|
25444
|
+
const fd = openSync10(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
25316
25445
|
try {
|
|
25317
25446
|
openedBefore = fstatSync2(fd);
|
|
25318
|
-
contents =
|
|
25447
|
+
contents = readFileSync13(fd);
|
|
25319
25448
|
openedAfter = fstatSync2(fd);
|
|
25320
25449
|
} finally {
|
|
25321
|
-
|
|
25450
|
+
closeSync9(fd);
|
|
25322
25451
|
}
|
|
25323
25452
|
const after = lstatSync4(path);
|
|
25324
25453
|
if (before.dev !== openedBefore.dev || before.ino !== openedBefore.ino || openedBefore.dev !== openedAfter.dev || openedBefore.ino !== openedAfter.ino || openedBefore.size !== openedAfter.size || openedBefore.mtimeMs !== openedAfter.mtimeMs || openedBefore.ctimeMs !== openedAfter.ctimeMs || after.dev !== openedAfter.dev || after.ino !== openedAfter.ino || after.size !== openedAfter.size || after.mtimeMs !== openedAfter.mtimeMs || after.ctimeMs !== openedAfter.ctimeMs || !openedAfter.isFile() || !after.isFile() || after.isSymbolicLink()) {
|
|
@@ -25333,7 +25462,7 @@ function resolveLegacyThreadFile(projectDir, value) {
|
|
|
25333
25462
|
size: after.size,
|
|
25334
25463
|
mtimeMs: after.mtimeMs,
|
|
25335
25464
|
ctimeMs: after.ctimeMs,
|
|
25336
|
-
digest:
|
|
25465
|
+
digest: createHash10("sha256").update(contents).digest("hex")
|
|
25337
25466
|
};
|
|
25338
25467
|
} catch {
|
|
25339
25468
|
return null;
|
|
@@ -25348,9 +25477,9 @@ function boardAuthorizesAdoption(board, slug) {
|
|
|
25348
25477
|
return !board.errorItems.some((item) => item.file === `${slug}.md`);
|
|
25349
25478
|
}
|
|
25350
25479
|
function ensureSafeDirectDirectory(parent, name) {
|
|
25351
|
-
const path =
|
|
25480
|
+
const path = join22(parent, name);
|
|
25352
25481
|
try {
|
|
25353
|
-
|
|
25482
|
+
mkdirSync11(path);
|
|
25354
25483
|
} catch (error) {
|
|
25355
25484
|
const code = error && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
25356
25485
|
if (code !== "EEXIST") throw error;
|
|
@@ -25358,7 +25487,7 @@ function ensureSafeDirectDirectory(parent, name) {
|
|
|
25358
25487
|
const stat2 = lstatSync4(path);
|
|
25359
25488
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) throw new Error("unsafe project directory");
|
|
25360
25489
|
const real = realpathSync5(path);
|
|
25361
|
-
if (
|
|
25490
|
+
if (dirname6(real) !== parent || basename4(real) !== name) throw new Error("unsafe project directory");
|
|
25362
25491
|
return real;
|
|
25363
25492
|
}
|
|
25364
25493
|
function scratchpadContent(title, kind = "claude") {
|
|
@@ -25421,14 +25550,14 @@ function writeScratchpad(projectDir, sessionId, title, kind = "claude") {
|
|
|
25421
25550
|
const threadsDir = ensureSafeDirectDirectory(frizzDir, "threads");
|
|
25422
25551
|
const dir = ensureSafeDirectDirectory(threadsDir, sessionId);
|
|
25423
25552
|
const rel = scratchpadRelPath(sessionId);
|
|
25424
|
-
const path =
|
|
25425
|
-
const tmp =
|
|
25553
|
+
const path = join22(dir, "scratch.md");
|
|
25554
|
+
const tmp = join22(dir, ".scratch.tmp");
|
|
25426
25555
|
try {
|
|
25427
|
-
|
|
25428
|
-
if (
|
|
25429
|
-
|
|
25556
|
+
writeFileSync7(tmp, scratchpadContent(title, kind), { flag: "wx", mode: 384 });
|
|
25557
|
+
if (existsSync8(path)) throw new Error("scratchpad already exists");
|
|
25558
|
+
renameSync6(tmp, path);
|
|
25430
25559
|
} catch (error) {
|
|
25431
|
-
|
|
25560
|
+
rmSync6(tmp, { force: true });
|
|
25432
25561
|
throw error;
|
|
25433
25562
|
}
|
|
25434
25563
|
return rel;
|
|
@@ -25446,8 +25575,8 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
25446
25575
|
}
|
|
25447
25576
|
]
|
|
25448
25577
|
});
|
|
25449
|
-
const bashBackgroundHook =
|
|
25450
|
-
const scratchpadStopHook =
|
|
25578
|
+
const bashBackgroundHook = join22(dirname6(hookScript), "bash-background.mjs");
|
|
25579
|
+
const scratchpadStopHook = join22(dirname6(hookScript), "scratchpad-stop.mjs");
|
|
25451
25580
|
return {
|
|
25452
25581
|
bypass_hook_trust: true,
|
|
25453
25582
|
hooks: {
|
|
@@ -25480,7 +25609,7 @@ function codexScratchpadHookConfig(hookScript, sessionId) {
|
|
|
25480
25609
|
}
|
|
25481
25610
|
function scratchpadHookScript() {
|
|
25482
25611
|
const plugin = workerPluginDir();
|
|
25483
|
-
return plugin ?
|
|
25612
|
+
return plugin ? join22(plugin, "hooks", "scratchpad.mjs") : void 0;
|
|
25484
25613
|
}
|
|
25485
25614
|
function composePrompt(sessionId, prompt, kind = "claude") {
|
|
25486
25615
|
const scratch = kind === "codex" ? `Your scratchpad is \`.frizz/threads/${sessionId}/scratch.md\` \u2014 an OPTIONAL scratch file kept for you, not a deliverable. A single direct task usually needs nothing in it, and writing in it never substitutes for doing the work. On a long effort it is useful crash insurance and a shared progress document for native sub-agents: keep the approach, what you rejected, and the human's decisions in it as you go, mid-work, then keep working; re-read it after any compaction or resume before asserting anything. Each native sub-agent should merge its own scoped progress into it rather than leaving the root as its sole writer, but must re-read before each edit, preserve all existing content, and never delete, truncate, reinitialize, move, or replace the whole file.` : `Your scratchpad is \`.frizz/threads/${sessionId}/scratch.md\` \u2014 an OPTIONAL scratch file kept for you, not a deliverable. A single direct task usually needs nothing in it, and writing in it never substitutes for doing the work. On a long effort it is useful crash insurance and the shared blackboard for your sub-agents: keep the approach, what you rejected, and the human's decisions in it as you go, mid-work, then keep working; re-read it after any compaction or resume, and pass its path to every sub-agent you dispatch. Each sub-agent should merge its own scoped progress into it rather than leaving the root as its sole writer, but must re-read before each edit, preserve all existing content, and never delete, truncate, reinitialize, move, or replace the whole file.`;
|
|
@@ -25497,12 +25626,12 @@ function scratchpadOrientation(sessionId, planPath, kind = "claude") {
|
|
|
25497
25626
|
return lines.join("\n");
|
|
25498
25627
|
}
|
|
25499
25628
|
function frizzConfigBlock(projectDir) {
|
|
25500
|
-
const path =
|
|
25629
|
+
const path = join22(projectDir, "FRIZZ.md");
|
|
25501
25630
|
let body;
|
|
25502
25631
|
try {
|
|
25503
25632
|
const st = statSync12(path);
|
|
25504
25633
|
if (!st.isFile() || st.size > FRIZZ_MD_MAX_BYTES) return "";
|
|
25505
|
-
body =
|
|
25634
|
+
body = readFileSync13(path, "utf8").trim();
|
|
25506
25635
|
} catch {
|
|
25507
25636
|
return "";
|
|
25508
25637
|
}
|
|
@@ -25516,7 +25645,7 @@ ${clipped}`;
|
|
|
25516
25645
|
}
|
|
25517
25646
|
function validPlanPath(projectDir, planPath) {
|
|
25518
25647
|
if (!planPath || !PLAN_PATH_RE.test(planPath)) return null;
|
|
25519
|
-
return
|
|
25648
|
+
return existsSync8(join22(projectDir, planPath)) ? planPath : null;
|
|
25520
25649
|
}
|
|
25521
25650
|
function workerPermissionMode(m) {
|
|
25522
25651
|
return m === "plan" ? "auto" : m;
|
|
@@ -25532,16 +25661,16 @@ function effectivePermissionMode(kind, mode) {
|
|
|
25532
25661
|
}
|
|
25533
25662
|
function systemPromptFlags(sessionId, system) {
|
|
25534
25663
|
if (!system) return [];
|
|
25535
|
-
|
|
25664
|
+
mkdirSync11(SYSTEM_PROMPT_DIR, { recursive: true });
|
|
25536
25665
|
const path = systemPromptPath(sessionId);
|
|
25537
|
-
|
|
25666
|
+
writeFileSync7(path, system);
|
|
25538
25667
|
return ["--append-system-prompt-file", path];
|
|
25539
25668
|
}
|
|
25540
25669
|
function resolveFrizzMcp(stateDir, moduleUrl = import.meta.url, env = process.env, slug) {
|
|
25541
25670
|
const pluginDir = resolveWorkerPluginDir(moduleUrl, env);
|
|
25542
25671
|
if (!pluginDir) return void 0;
|
|
25543
|
-
const scriptPath =
|
|
25544
|
-
if (!
|
|
25672
|
+
const scriptPath = join22(pluginDir, "bin", FRIZZ_MCP.script);
|
|
25673
|
+
if (!existsSync8(scriptPath)) return void 0;
|
|
25545
25674
|
return { scriptPath, stateDir, ...slug ? { slug } : {} };
|
|
25546
25675
|
}
|
|
25547
25676
|
function claudeMcpConfig(mcp) {
|
|
@@ -25582,13 +25711,13 @@ function buildClaudeCommand(opts) {
|
|
|
25582
25711
|
}
|
|
25583
25712
|
function resolveWorkerPluginDir(moduleUrl = import.meta.url, env = process.env) {
|
|
25584
25713
|
const override = env.FRIZZ_WORKER_PLUGIN_DIR;
|
|
25585
|
-
if (override &&
|
|
25714
|
+
if (override && existsSync8(join22(override, ".claude-plugin", "plugin.json")))
|
|
25586
25715
|
return override;
|
|
25587
|
-
let current =
|
|
25716
|
+
let current = dirname6(fileURLToPath2(moduleUrl));
|
|
25588
25717
|
for (; ; ) {
|
|
25589
|
-
const candidate =
|
|
25590
|
-
if (
|
|
25591
|
-
const parent =
|
|
25718
|
+
const candidate = join22(current, "cc-worker");
|
|
25719
|
+
if (existsSync8(join22(candidate, ".claude-plugin", "plugin.json"))) return candidate;
|
|
25720
|
+
const parent = dirname6(current);
|
|
25592
25721
|
if (parent === current) return void 0;
|
|
25593
25722
|
current = parent;
|
|
25594
25723
|
}
|
|
@@ -25629,12 +25758,12 @@ function buildClaudeResumeCommand(opts) {
|
|
|
25629
25758
|
}
|
|
25630
25759
|
function createDispatcher(deps) {
|
|
25631
25760
|
const readBoardSource = deps.readBoard ?? readBoard;
|
|
25632
|
-
const frizzDir =
|
|
25761
|
+
const frizzDir = join22(deps.project.dir, ".frizz");
|
|
25633
25762
|
const adoptionRuntime = deps.adoptionRuntime ?? productionRuntime;
|
|
25634
25763
|
function cleanupPrewrites(built) {
|
|
25635
25764
|
for (const path of new Set(built.prewrite.map((file) => file.path))) {
|
|
25636
25765
|
try {
|
|
25637
|
-
|
|
25766
|
+
rmSync6(path, { force: true });
|
|
25638
25767
|
} catch {
|
|
25639
25768
|
}
|
|
25640
25769
|
}
|
|
@@ -25642,7 +25771,7 @@ function createDispatcher(deps) {
|
|
|
25642
25771
|
function cleanupDispatchFiles(scratchRel, built, sessionId) {
|
|
25643
25772
|
cleanupPrewrites(built);
|
|
25644
25773
|
try {
|
|
25645
|
-
|
|
25774
|
+
rmSync6(join22(deps.project.dir, scratchRel), { force: true });
|
|
25646
25775
|
} catch {
|
|
25647
25776
|
}
|
|
25648
25777
|
cleanupAdoptionSessionFiles(deps.project.dir, sessionId);
|
|
@@ -26013,28 +26142,28 @@ var init_dispatch = __esm({
|
|
|
26013
26142
|
|
|
26014
26143
|
// packages/server/src/plan-files.ts
|
|
26015
26144
|
import {
|
|
26016
|
-
closeSync as
|
|
26145
|
+
closeSync as closeSync10,
|
|
26017
26146
|
constants as constants2,
|
|
26018
26147
|
fstatSync as fstatSync3,
|
|
26019
26148
|
lstatSync as lstatSync5,
|
|
26020
|
-
openSync as
|
|
26021
|
-
readFileSync as
|
|
26149
|
+
openSync as openSync11,
|
|
26150
|
+
readFileSync as readFileSync14,
|
|
26022
26151
|
readdirSync as readdirSync8,
|
|
26023
26152
|
realpathSync as realpathSync6,
|
|
26024
26153
|
unlinkSync as unlinkSync4
|
|
26025
26154
|
} from "node:fs";
|
|
26026
|
-
import { createHash as
|
|
26027
|
-
import { basename as basename5, dirname as
|
|
26155
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
26156
|
+
import { basename as basename5, dirname as dirname7, join as join23 } from "node:path";
|
|
26028
26157
|
function sameStat(a, b) {
|
|
26029
26158
|
return a.dev === b.dev && a.ino === b.ino && a.mode === b.mode && a.size === b.size && a.mtimeMs === b.mtimeMs && a.ctimeMs === b.ctimeMs;
|
|
26030
26159
|
}
|
|
26031
26160
|
function directDirectory(parentRealPath, name) {
|
|
26032
26161
|
try {
|
|
26033
|
-
const path =
|
|
26162
|
+
const path = join23(parentRealPath, name);
|
|
26034
26163
|
const stat2 = lstatSync5(path);
|
|
26035
26164
|
if (!stat2.isDirectory() || stat2.isSymbolicLink()) return null;
|
|
26036
26165
|
const realPath = realpathSync6(path);
|
|
26037
|
-
if (
|
|
26166
|
+
if (dirname7(realPath) !== parentRealPath || basename5(realPath) !== name) return null;
|
|
26038
26167
|
return { path, realPath, stat: stat2 };
|
|
26039
26168
|
} catch {
|
|
26040
26169
|
return null;
|
|
@@ -26068,22 +26197,22 @@ function resolvePlanFile(projectDir, value, hooks = {}) {
|
|
|
26068
26197
|
const directoryBefore = planDirectory(projectDir);
|
|
26069
26198
|
if (!directoryBefore) return null;
|
|
26070
26199
|
hooks.afterDirectoryCheck?.();
|
|
26071
|
-
const path =
|
|
26200
|
+
const path = join23(directoryBefore.plans.realPath, filename);
|
|
26072
26201
|
const before = lstatSync5(path);
|
|
26073
26202
|
if (!before.isFile() || before.isSymbolicLink()) return null;
|
|
26074
26203
|
const realPath = realpathSync6(path);
|
|
26075
|
-
if (
|
|
26204
|
+
if (dirname7(realPath) !== directoryBefore.plans.realPath || basename5(realPath) !== filename) return null;
|
|
26076
26205
|
hooks.afterFileCheck?.();
|
|
26077
26206
|
let contents;
|
|
26078
26207
|
let openedBefore;
|
|
26079
26208
|
let openedAfter;
|
|
26080
|
-
const fd =
|
|
26209
|
+
const fd = openSync11(path, constants2.O_RDONLY | constants2.O_NOFOLLOW);
|
|
26081
26210
|
try {
|
|
26082
26211
|
openedBefore = fstatSync3(fd);
|
|
26083
|
-
contents =
|
|
26212
|
+
contents = readFileSync14(fd);
|
|
26084
26213
|
openedAfter = fstatSync3(fd);
|
|
26085
26214
|
} finally {
|
|
26086
|
-
|
|
26215
|
+
closeSync10(fd);
|
|
26087
26216
|
}
|
|
26088
26217
|
const after = lstatSync5(path);
|
|
26089
26218
|
const realPathAfter = realpathSync6(path);
|
|
@@ -26100,7 +26229,7 @@ function resolvePlanFile(projectDir, value, hooks = {}) {
|
|
|
26100
26229
|
size: after.size,
|
|
26101
26230
|
mtimeMs: after.mtimeMs,
|
|
26102
26231
|
ctimeMs: after.ctimeMs,
|
|
26103
|
-
digest:
|
|
26232
|
+
digest: createHash11("sha256").update(contents).digest("hex")
|
|
26104
26233
|
};
|
|
26105
26234
|
} catch {
|
|
26106
26235
|
return null;
|
|
@@ -26144,10 +26273,10 @@ var init_plan_files = __esm({
|
|
|
26144
26273
|
|
|
26145
26274
|
// packages/server/src/board.ts
|
|
26146
26275
|
import {
|
|
26147
|
-
existsSync as
|
|
26276
|
+
existsSync as existsSync9,
|
|
26148
26277
|
watch as fsWatch
|
|
26149
26278
|
} from "node:fs";
|
|
26150
|
-
import { join as
|
|
26279
|
+
import { join as join24 } from "node:path";
|
|
26151
26280
|
import watcher from "@parcel/watcher";
|
|
26152
26281
|
function appServerTurnStalled(liveness, lastActivityAt, nowMs) {
|
|
26153
26282
|
if (!liveness) return false;
|
|
@@ -26253,7 +26382,7 @@ function deriveAwaitingBackground(row, tele, runtime, hasActionableInteraction =
|
|
|
26253
26382
|
}
|
|
26254
26383
|
function scratchpadPathIfExists(projectDir, sessionId) {
|
|
26255
26384
|
const rel = scratchpadRelPath(sessionId);
|
|
26256
|
-
return
|
|
26385
|
+
return existsSync9(join24(projectDir, rel)) ? rel : void 0;
|
|
26257
26386
|
}
|
|
26258
26387
|
function resolveSessionProfile(row, tele) {
|
|
26259
26388
|
const persistedModel = row.model?.trim() || void 0;
|
|
@@ -26626,7 +26755,7 @@ function createBoard(project, storage, bus, tailer, bootId, deps = {}) {
|
|
|
26626
26755
|
if (parcelSub || stopped) return Promise.resolve();
|
|
26627
26756
|
if (watchSetup) return watchSetup;
|
|
26628
26757
|
const setup = (async () => {
|
|
26629
|
-
const next = await subscribe(
|
|
26758
|
+
const next = await subscribe(join24(project.dir, ".frizz"), () => scheduleRebuild());
|
|
26630
26759
|
if (stopped) {
|
|
26631
26760
|
await next.unsubscribe();
|
|
26632
26761
|
return;
|
|
@@ -27166,14 +27295,14 @@ function createGithubReviewFetcher(deps = {}) {
|
|
|
27166
27295
|
pending = /* @__PURE__ */ new Map();
|
|
27167
27296
|
if (batch.size === 0) return;
|
|
27168
27297
|
if (now() < notBeforeMs) {
|
|
27169
|
-
for (const entry of batch.values()) for (const
|
|
27298
|
+
for (const entry of batch.values()) for (const resolve10 of entry.resolve) resolve10({ status: "deferred" });
|
|
27170
27299
|
return;
|
|
27171
27300
|
}
|
|
27172
27301
|
const entries = [...batch.values()];
|
|
27173
27302
|
for (let offset = 0; offset < entries.length; offset += MAX_REFS_PER_REQUEST) {
|
|
27174
27303
|
const chunk = entries.slice(offset, offset + MAX_REFS_PER_REQUEST);
|
|
27175
27304
|
if (offset > 0 && now() < rateLimitBlockedUntilMs) {
|
|
27176
|
-
for (const entry of chunk) for (const
|
|
27305
|
+
for (const entry of chunk) for (const resolve10 of entry.resolve) resolve10({ status: "deferred" });
|
|
27177
27306
|
continue;
|
|
27178
27307
|
}
|
|
27179
27308
|
let results;
|
|
@@ -27193,15 +27322,15 @@ function createGithubReviewFetcher(deps = {}) {
|
|
|
27193
27322
|
status: "error",
|
|
27194
27323
|
failure: { kind: "shape", message: `No GitHub result for ${refKey(entry.ref)}` }
|
|
27195
27324
|
};
|
|
27196
|
-
for (const
|
|
27325
|
+
for (const resolve10 of entry.resolve) resolve10(result);
|
|
27197
27326
|
}
|
|
27198
27327
|
}
|
|
27199
27328
|
};
|
|
27200
|
-
return (ref) => new Promise((
|
|
27329
|
+
return (ref) => new Promise((resolve10) => {
|
|
27201
27330
|
const key = refKey(ref);
|
|
27202
27331
|
const existing = pending.get(key);
|
|
27203
|
-
if (existing) existing.resolve.push(
|
|
27204
|
-
else pending.set(key, { ref, resolve: [
|
|
27332
|
+
if (existing) existing.resolve.push(resolve10);
|
|
27333
|
+
else pending.set(key, { ref, resolve: [resolve10] });
|
|
27205
27334
|
if (!flushScheduled) {
|
|
27206
27335
|
flushScheduled = true;
|
|
27207
27336
|
queueMicrotask(() => {
|
|
@@ -27226,7 +27355,7 @@ var init_github_review = __esm({
|
|
|
27226
27355
|
// packages/server/src/scheduler.ts
|
|
27227
27356
|
import { execFile as execFile5 } from "node:child_process";
|
|
27228
27357
|
import { promisify as promisify5 } from "node:util";
|
|
27229
|
-
import { createHash as
|
|
27358
|
+
import { createHash as createHash12, randomUUID as randomUUID13 } from "node:crypto";
|
|
27230
27359
|
function parsePrRef(value) {
|
|
27231
27360
|
const m = value.trim().match(PR_REF_RE);
|
|
27232
27361
|
if (!m) return void 0;
|
|
@@ -27307,7 +27436,7 @@ function fenceIdentity(hints, fenceAt) {
|
|
|
27307
27436
|
return `${fenceAt ?? ""}${hintId}`;
|
|
27308
27437
|
}
|
|
27309
27438
|
function wakeDeliveryId(slug, sessionId, fenceId) {
|
|
27310
|
-
return
|
|
27439
|
+
return createHash12("sha256").update(slug).update("\0").update(sessionId).update("\0").update(fenceId).digest("hex");
|
|
27311
27440
|
}
|
|
27312
27441
|
function limitFenceId(fault) {
|
|
27313
27442
|
return `${LIMIT_FENCE_PREFIX}${fault.at}`;
|
|
@@ -27326,7 +27455,7 @@ function isReportFenceId(fenceId) {
|
|
|
27326
27455
|
return fenceId.startsWith(`${REPORT_FENCE_PREFIX}:`);
|
|
27327
27456
|
}
|
|
27328
27457
|
function snoozeFenceId(until, prompt) {
|
|
27329
|
-
const digest =
|
|
27458
|
+
const digest = createHash12("sha256").update(prompt).digest("hex").slice(0, 16);
|
|
27330
27459
|
return `${SNOOZE_FENCE_PREFIX}:${until}:${digest}`;
|
|
27331
27460
|
}
|
|
27332
27461
|
function isSnoozeFenceId(fenceId) {
|
|
@@ -28352,7 +28481,7 @@ var init_resume = __esm({
|
|
|
28352
28481
|
});
|
|
28353
28482
|
|
|
28354
28483
|
// packages/server/src/backend/claude.ts
|
|
28355
|
-
import { join as
|
|
28484
|
+
import { join as join25 } from "node:path";
|
|
28356
28485
|
function toolResultText2(content) {
|
|
28357
28486
|
if (typeof content === "string") return content;
|
|
28358
28487
|
if (!Array.isArray(content)) return "";
|
|
@@ -28441,7 +28570,7 @@ function createClaudeBackend(opts) {
|
|
|
28441
28570
|
return { argv, env: claudeWorkerEnvironment(), prewrite: [] };
|
|
28442
28571
|
},
|
|
28443
28572
|
transcriptPath(sessionId) {
|
|
28444
|
-
return
|
|
28573
|
+
return join25(opts.logDir, `${sessionId}.jsonl`);
|
|
28445
28574
|
},
|
|
28446
28575
|
parseLine(line) {
|
|
28447
28576
|
return parseClaudeLine(line);
|
|
@@ -28936,24 +29065,24 @@ CI: \`gh pr checks {n} -R {repo}\``;
|
|
|
28936
29065
|
});
|
|
28937
29066
|
|
|
28938
29067
|
// packages/server/src/backend/codex-app-server-diagnostics.ts
|
|
28939
|
-
import { appendFileSync as appendFileSync3, mkdirSync as
|
|
28940
|
-
import { join as
|
|
29068
|
+
import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync12, renameSync as renameSync7, statSync as statSync13 } from "node:fs";
|
|
29069
|
+
import { join as join26 } from "node:path";
|
|
28941
29070
|
function codexDiagnosticLogPath(stateDir, projectId) {
|
|
28942
|
-
return
|
|
29071
|
+
return join26(stateDir, "codex-app-server", `${projectId}.diagnostics.log`);
|
|
28943
29072
|
}
|
|
28944
29073
|
function createCodexDiagnosticSink(stateDir, projectId, now = () => /* @__PURE__ */ new Date()) {
|
|
28945
|
-
const dir =
|
|
29074
|
+
const dir = join26(stateDir, "codex-app-server");
|
|
28946
29075
|
const path = codexDiagnosticLogPath(stateDir, projectId);
|
|
28947
29076
|
let ensured = false;
|
|
28948
29077
|
return (event) => {
|
|
28949
29078
|
if (event.event === "stderr") return;
|
|
28950
29079
|
try {
|
|
28951
29080
|
if (!ensured) {
|
|
28952
|
-
|
|
29081
|
+
mkdirSync12(dir, { recursive: true });
|
|
28953
29082
|
ensured = true;
|
|
28954
29083
|
}
|
|
28955
29084
|
try {
|
|
28956
|
-
if (statSync13(path).size > MAX_BYTES2)
|
|
29085
|
+
if (statSync13(path).size > MAX_BYTES2) renameSync7(path, `${path}.1`);
|
|
28957
29086
|
} catch {
|
|
28958
29087
|
}
|
|
28959
29088
|
appendFileSync3(path, `${JSON.stringify({ at: now().toISOString(), ...event })}
|
|
@@ -28974,13 +29103,13 @@ var init_codex_app_server_diagnostics = __esm({
|
|
|
28974
29103
|
import { execFile as execFile7 } from "node:child_process";
|
|
28975
29104
|
import { readdirSync as readdirSync9, unlinkSync as unlinkSync5 } from "node:fs";
|
|
28976
29105
|
import { connect as connectSocket } from "node:net";
|
|
28977
|
-
import { join as
|
|
29106
|
+
import { join as join27 } from "node:path";
|
|
28978
29107
|
function sweepStaleSockets(options, deps = {}) {
|
|
28979
29108
|
if (process.platform === "win32") return;
|
|
28980
29109
|
const keep = new Set(options.keep ?? []);
|
|
28981
29110
|
let candidates;
|
|
28982
29111
|
try {
|
|
28983
|
-
candidates = (deps.readdir ?? readdirSync9)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) =>
|
|
29112
|
+
candidates = (deps.readdir ?? readdirSync9)(options.dir).filter((name) => name.startsWith(options.prefix) && name.endsWith(".sock")).map((name) => join27(options.dir, name)).filter((path) => !keep.has(path));
|
|
28984
29113
|
} catch {
|
|
28985
29114
|
return;
|
|
28986
29115
|
}
|
|
@@ -29032,7 +29161,7 @@ var init_stale_socket_sweep = __esm({
|
|
|
29032
29161
|
|
|
29033
29162
|
// packages/server/src/orphan-reaper.ts
|
|
29034
29163
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
29035
|
-
import { dirname as
|
|
29164
|
+
import { dirname as dirname8 } from "node:path";
|
|
29036
29165
|
function firstTokenBasename(command) {
|
|
29037
29166
|
const first = command.trimStart().split(/\s+/, 1)[0] ?? "";
|
|
29038
29167
|
const slash = first.lastIndexOf("/");
|
|
@@ -29243,7 +29372,7 @@ function sweepOrphansOnce(deps = {}) {
|
|
|
29243
29372
|
}
|
|
29244
29373
|
function sweepStaleBrokerSockets() {
|
|
29245
29374
|
try {
|
|
29246
|
-
sweepStaleSockets({ dir:
|
|
29375
|
+
sweepStaleSockets({ dir: dirname8(claudeBrokerSocketPath("", "")), prefix: CLAUDE_BROKER_SOCKET_PREFIX });
|
|
29247
29376
|
} catch {
|
|
29248
29377
|
}
|
|
29249
29378
|
}
|
|
@@ -29293,7 +29422,7 @@ var init_orphan_reaper = __esm({
|
|
|
29293
29422
|
});
|
|
29294
29423
|
|
|
29295
29424
|
// packages/server/src/context.ts
|
|
29296
|
-
import { join as
|
|
29425
|
+
import { join as join28 } from "node:path";
|
|
29297
29426
|
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
29298
29427
|
function reconcileSessions(storage) {
|
|
29299
29428
|
for (const row of storage.allSessions()) {
|
|
@@ -29428,7 +29557,7 @@ async function createContext(opts = {}) {
|
|
|
29428
29557
|
}
|
|
29429
29558
|
function createContextUnchecked(opts, resources) {
|
|
29430
29559
|
const project = opts.project ?? resolveProject();
|
|
29431
|
-
const dbPath =
|
|
29560
|
+
const dbPath = join28(project.stateDir, "ui.db");
|
|
29432
29561
|
const storage = createStorage(dbPath);
|
|
29433
29562
|
resources.storage = storage;
|
|
29434
29563
|
const bus = new Bus();
|
|
@@ -32418,8 +32547,8 @@ var init_server = __esm({
|
|
|
32418
32547
|
});
|
|
32419
32548
|
|
|
32420
32549
|
// packages/server/src/repair.ts
|
|
32421
|
-
import { existsSync as
|
|
32422
|
-
import { basename as basename6, dirname as
|
|
32550
|
+
import { existsSync as existsSync10, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "node:fs";
|
|
32551
|
+
import { basename as basename6, dirname as dirname9, resolve as resolve7 } from "node:path";
|
|
32423
32552
|
function quoteValue(v) {
|
|
32424
32553
|
if (/^[\w./#:+-]+$/.test(v)) return v;
|
|
32425
32554
|
return `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
@@ -32429,12 +32558,12 @@ function deriveTitle(body, slug) {
|
|
|
32429
32558
|
return m ? m[1].trim() : slug;
|
|
32430
32559
|
}
|
|
32431
32560
|
function repairThreadFile(frizzDir, file) {
|
|
32432
|
-
const root =
|
|
32433
|
-
const abs =
|
|
32434
|
-
if (
|
|
32561
|
+
const root = resolve7(frizzDir);
|
|
32562
|
+
const abs = resolve7(root, file);
|
|
32563
|
+
if (dirname9(abs) !== root) throw new RepairError(`refusing to repair "${file}": not directly under .frizz/`);
|
|
32435
32564
|
if (!abs.endsWith(".md")) throw new RepairError(`refusing to repair "${file}": not a .md thread file`);
|
|
32436
|
-
if (!
|
|
32437
|
-
const content =
|
|
32565
|
+
if (!existsSync10(abs)) throw new RepairError(`no thread file to repair: ${basename6(abs)}`);
|
|
32566
|
+
const content = readFileSync15(abs, "utf8");
|
|
32438
32567
|
const firstLine = content.replace(/^/, "").split(/\r?\n/).find((l) => l.trim() !== "");
|
|
32439
32568
|
if (firstLine?.trim() === "---") {
|
|
32440
32569
|
throw new RepairError(`${basename6(abs)} already opens with a "---" block \u2014 repair only heals a MISSING frontmatter block`);
|
|
@@ -32449,7 +32578,7 @@ function repairThreadFile(frizzDir, file) {
|
|
|
32449
32578
|
"---",
|
|
32450
32579
|
""
|
|
32451
32580
|
].join("\n");
|
|
32452
|
-
|
|
32581
|
+
writeFileSync8(abs, frontmatter + content);
|
|
32453
32582
|
return { slug };
|
|
32454
32583
|
}
|
|
32455
32584
|
var RepairError, REPAIR_STATUS_TEXT;
|
|
@@ -32467,7 +32596,7 @@ var init_repair = __esm({
|
|
|
32467
32596
|
});
|
|
32468
32597
|
|
|
32469
32598
|
// cc-worker/hooks/bash-background.mjs
|
|
32470
|
-
import { readFileSync as
|
|
32599
|
+
import { readFileSync as readFileSync16 } from "node:fs";
|
|
32471
32600
|
import { basename as basename7 } from "node:path";
|
|
32472
32601
|
import { pathToFileURL } from "node:url";
|
|
32473
32602
|
function emit(obj) {
|
|
@@ -32616,7 +32745,7 @@ var init_bash_background = __esm({
|
|
|
32616
32745
|
if (isDirectHookExecution(process.argv[1], import.meta.url)) {
|
|
32617
32746
|
try {
|
|
32618
32747
|
const env = process.argv.includes("--frizz-thread") ? { ...process.env, FRIZZ_THREAD: process.env.FRIZZ_THREAD || "codex-worker" } : process.env;
|
|
32619
|
-
emit(evaluateBashBackgroundHook(JSON.parse(
|
|
32748
|
+
emit(evaluateBashBackgroundHook(JSON.parse(readFileSync16(0, "utf8")), env));
|
|
32620
32749
|
} catch {
|
|
32621
32750
|
emit({});
|
|
32622
32751
|
}
|
|
@@ -32625,11 +32754,11 @@ var init_bash_background = __esm({
|
|
|
32625
32754
|
});
|
|
32626
32755
|
|
|
32627
32756
|
// packages/server/src/transcript.ts
|
|
32628
|
-
import { closeSync as
|
|
32629
|
-
import { createHash as
|
|
32757
|
+
import { closeSync as closeSync11, existsSync as existsSync11, fstatSync as fstatSync4, mkdirSync as mkdirSync13, openSync as openSync12, readdirSync as readdirSync10, readFileSync as readFileSync17, readSync as readSync6, renameSync as renameSync8, statSync as statSync14, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "node:fs";
|
|
32758
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
32630
32759
|
import { StringDecoder as StringDecoder4 } from "node:string_decoder";
|
|
32631
|
-
import { join as
|
|
32632
|
-
import { homedir as
|
|
32760
|
+
import { join as join29 } from "node:path";
|
|
32761
|
+
import { homedir as homedir12, tmpdir as tmpdir4 } from "node:os";
|
|
32633
32762
|
function isInjectedNoise(text) {
|
|
32634
32763
|
const t = text.trimStart();
|
|
32635
32764
|
return NOISE_PREFIXES.some((p) => t.startsWith(p));
|
|
@@ -33121,14 +33250,14 @@ function pruneScreenshotCache() {
|
|
|
33121
33250
|
if (entries.length <= SCREENSHOT_CACHE_MAX) return;
|
|
33122
33251
|
const byMtime = entries.map((n) => {
|
|
33123
33252
|
try {
|
|
33124
|
-
return { n, m: statSync14(
|
|
33253
|
+
return { n, m: statSync14(join29(SCREENSHOT_CACHE_DIR, n)).mtimeMs };
|
|
33125
33254
|
} catch {
|
|
33126
33255
|
return { n, m: 0 };
|
|
33127
33256
|
}
|
|
33128
33257
|
}).sort((a, b) => b.m - a.m);
|
|
33129
33258
|
for (const { n } of byMtime.slice(SCREENSHOT_CACHE_MAX)) {
|
|
33130
33259
|
try {
|
|
33131
|
-
unlinkSync6(
|
|
33260
|
+
unlinkSync6(join29(SCREENSHOT_CACHE_DIR, n));
|
|
33132
33261
|
} catch {
|
|
33133
33262
|
}
|
|
33134
33263
|
}
|
|
@@ -33157,17 +33286,17 @@ function persistDataUrlImage(dataUrl, idKey) {
|
|
|
33157
33286
|
function persistBase64Image(mediaType, data, idKey) {
|
|
33158
33287
|
const ext = IMAGE_MEDIA_EXT[typeof mediaType === "string" ? mediaType.toLowerCase() : ""];
|
|
33159
33288
|
if (!ext || !data) return void 0;
|
|
33160
|
-
const name =
|
|
33161
|
-
const path =
|
|
33289
|
+
const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
33290
|
+
const path = join29(SCREENSHOT_CACHE_DIR, `${name}.${ext}`);
|
|
33162
33291
|
try {
|
|
33163
|
-
if (
|
|
33292
|
+
if (existsSync11(path)) return path;
|
|
33164
33293
|
if (data.length > SCREENSHOT_MAX_BASE64) return void 0;
|
|
33165
33294
|
const buf = Buffer.from(data, "base64");
|
|
33166
33295
|
if (buf.length === 0 || !looksLikeImage(buf, ext)) return void 0;
|
|
33167
|
-
|
|
33168
|
-
const tmp =
|
|
33169
|
-
|
|
33170
|
-
|
|
33296
|
+
mkdirSync13(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
33297
|
+
const tmp = join29(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
33298
|
+
writeFileSync9(tmp, buf);
|
|
33299
|
+
renameSync8(tmp, path);
|
|
33171
33300
|
pruneScreenshotCache();
|
|
33172
33301
|
return path;
|
|
33173
33302
|
} catch {
|
|
@@ -33179,17 +33308,17 @@ function persistSentFile(srcPath, idKey) {
|
|
|
33179
33308
|
if (!ATTACHMENT_IMAGE_EXTENSIONS.includes(ext)) return void 0;
|
|
33180
33309
|
const outExt = ext === "jpeg" ? "jpg" : ext;
|
|
33181
33310
|
try {
|
|
33182
|
-
const name =
|
|
33183
|
-
const dest =
|
|
33184
|
-
if (
|
|
33311
|
+
const name = createHash13("sha256").update(idKey).digest("hex").slice(0, 32);
|
|
33312
|
+
const dest = join29(SCREENSHOT_CACHE_DIR, `${name}.${outExt}`);
|
|
33313
|
+
if (existsSync11(dest)) return dest;
|
|
33185
33314
|
const size = statSync14(srcPath).size;
|
|
33186
33315
|
if (size === 0 || size > SENT_IMAGE_MAX_BYTES) return void 0;
|
|
33187
|
-
const buf =
|
|
33316
|
+
const buf = readFileSync17(srcPath);
|
|
33188
33317
|
if (!looksLikeImage(buf, outExt)) return void 0;
|
|
33189
|
-
|
|
33190
|
-
const tmp =
|
|
33191
|
-
|
|
33192
|
-
|
|
33318
|
+
mkdirSync13(SCREENSHOT_CACHE_DIR, { recursive: true });
|
|
33319
|
+
const tmp = join29(SCREENSHOT_CACHE_DIR, `.${name}.${process.pid}.${screenshotTmpSeq++}.tmp`);
|
|
33320
|
+
writeFileSync9(tmp, buf);
|
|
33321
|
+
renameSync8(tmp, dest);
|
|
33193
33322
|
pruneScreenshotCache();
|
|
33194
33323
|
return dest;
|
|
33195
33324
|
} catch {
|
|
@@ -33536,11 +33665,11 @@ function retainedFoldEntry(path, identityPrefix, fileId, size) {
|
|
|
33536
33665
|
return { entry, hit };
|
|
33537
33666
|
}
|
|
33538
33667
|
function readTranscript(project, sessionId) {
|
|
33539
|
-
const path =
|
|
33668
|
+
const path = join29(homedir12(), ".claude", "projects", project.cwdSlug, `${sessionId}.jsonl`);
|
|
33540
33669
|
const identityPrefix = `claude:${sessionId}`;
|
|
33541
33670
|
let fd;
|
|
33542
33671
|
try {
|
|
33543
|
-
fd =
|
|
33672
|
+
fd = openSync12(path, "r");
|
|
33544
33673
|
const st = fstatSync4(fd);
|
|
33545
33674
|
const size = st.size;
|
|
33546
33675
|
const fileId = `${st.dev}:${st.ino}:${Math.trunc(st.birthtimeMs)}`;
|
|
@@ -33559,12 +33688,12 @@ function readTranscript(project, sessionId) {
|
|
|
33559
33688
|
} catch {
|
|
33560
33689
|
return [];
|
|
33561
33690
|
} finally {
|
|
33562
|
-
if (fd !== void 0)
|
|
33691
|
+
if (fd !== void 0) closeSync11(fd);
|
|
33563
33692
|
}
|
|
33564
33693
|
}
|
|
33565
33694
|
function verifyIncrementalParse(path, identityPrefix, incremental) {
|
|
33566
33695
|
try {
|
|
33567
|
-
const fresh = parseTranscript(
|
|
33696
|
+
const fresh = parseTranscript(readFileSync17(path, "utf8"), identityPrefix);
|
|
33568
33697
|
const a = JSON.stringify(incremental);
|
|
33569
33698
|
const b = JSON.stringify(fresh);
|
|
33570
33699
|
if (a !== b) {
|
|
@@ -33584,7 +33713,7 @@ function verifyIncrementalParse(path, identityPrefix, incremental) {
|
|
|
33584
33713
|
}
|
|
33585
33714
|
}
|
|
33586
33715
|
function logDirOf(project) {
|
|
33587
|
-
return
|
|
33716
|
+
return join29(homedir12(), ".claude", "projects", project.cwdSlug);
|
|
33588
33717
|
}
|
|
33589
33718
|
function projectCodexTranscript(raw2, identityPrefix = "codex") {
|
|
33590
33719
|
const out = [];
|
|
@@ -33842,7 +33971,7 @@ function latestTranscriptWindow(messages) {
|
|
|
33842
33971
|
);
|
|
33843
33972
|
if (tools.length === 0) continue;
|
|
33844
33973
|
pinned.push({
|
|
33845
|
-
sourceId: `pinned-bg:${
|
|
33974
|
+
sourceId: `pinned-bg:${createHash13("sha256").update(message.sourceId).digest("base64url").slice(0, 24)}`,
|
|
33846
33975
|
pinnedFromSourceId: message.sourceId,
|
|
33847
33976
|
role: "assistant",
|
|
33848
33977
|
text: "",
|
|
@@ -34495,7 +34624,7 @@ function sourceForThread(project, storage, slug, backendFor) {
|
|
|
34495
34624
|
if (row) {
|
|
34496
34625
|
const backend = row.backend === "codex" ? "codex" : "claude";
|
|
34497
34626
|
const nativeId = backend === "codex" ? row.agent_session_id ?? row.session_id : row.transcript_id ?? row.session_id;
|
|
34498
|
-
const path = backend === "codex" ? (backendFor?.("codex") ?? defaultCodexBackend()).transcriptPath(nativeId) :
|
|
34627
|
+
const path = backend === "codex" ? (backendFor?.("codex") ?? defaultCodexBackend()).transcriptPath(nativeId) : join29(logDirOf(project), `${nativeId}.jsonl`);
|
|
34499
34628
|
if (!path) return void 0;
|
|
34500
34629
|
return {
|
|
34501
34630
|
slug,
|
|
@@ -34513,7 +34642,7 @@ function sourceForThread(project, storage, slug, backendFor) {
|
|
|
34513
34642
|
nativeId: slug,
|
|
34514
34643
|
backend: "claude",
|
|
34515
34644
|
runtimeGeneration: 0,
|
|
34516
|
-
path:
|
|
34645
|
+
path: join29(logDirOf(project), `${slug}.jsonl`)
|
|
34517
34646
|
};
|
|
34518
34647
|
}
|
|
34519
34648
|
function discoveredClaudeSource(project, storage, slug, expectedNativeId) {
|
|
@@ -34534,13 +34663,13 @@ function discoveredClaudeSource(project, storage, slug, expectedNativeId) {
|
|
|
34534
34663
|
nativeId,
|
|
34535
34664
|
backend: "claude",
|
|
34536
34665
|
runtimeGeneration: row.runtime_generation ?? 0,
|
|
34537
|
-
path:
|
|
34666
|
+
path: join29(logDirOf(project), `${nativeId}.jsonl`)
|
|
34538
34667
|
};
|
|
34539
34668
|
}
|
|
34540
34669
|
function fixedSnapshot(source) {
|
|
34541
34670
|
let fd;
|
|
34542
34671
|
try {
|
|
34543
|
-
fd =
|
|
34672
|
+
fd = openSync12(source.path, "r");
|
|
34544
34673
|
const before = fstatSync4(fd);
|
|
34545
34674
|
if (!Number.isSafeInteger(before.size) || before.size < 0) throw new Error("transcript is too large to page safely");
|
|
34546
34675
|
const bytes = Buffer.allocUnsafe(before.size);
|
|
@@ -34555,7 +34684,7 @@ function fixedSnapshot(source) {
|
|
|
34555
34684
|
throw new Error("transcript changed while it was being read; retry");
|
|
34556
34685
|
}
|
|
34557
34686
|
const fileKey = `${before.dev}:${before.ino}:${Math.trunc(before.birthtimeMs)}`;
|
|
34558
|
-
const transcriptKey =
|
|
34687
|
+
const transcriptKey = createHash13("sha256").update(`${source.slug}\0${source.sessionId}\0${source.nativeId}\0${source.backend}\0${source.runtimeGeneration}\0${fileKey}`).digest("base64url").slice(0, 32);
|
|
34559
34688
|
let rawText;
|
|
34560
34689
|
return {
|
|
34561
34690
|
...source,
|
|
@@ -34571,7 +34700,7 @@ function fixedSnapshot(source) {
|
|
|
34571
34700
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return void 0;
|
|
34572
34701
|
throw error;
|
|
34573
34702
|
} finally {
|
|
34574
|
-
if (fd !== void 0)
|
|
34703
|
+
if (fd !== void 0) closeSync11(fd);
|
|
34575
34704
|
}
|
|
34576
34705
|
}
|
|
34577
34706
|
function projectSnapshot(snapshot) {
|
|
@@ -34586,7 +34715,7 @@ function projectSnapshot(snapshot) {
|
|
|
34586
34715
|
return retireStaleQueuedBubbles([...entry.fold.allMessages()]);
|
|
34587
34716
|
}
|
|
34588
34717
|
function digestPrefix(bytes, length = bytes.length) {
|
|
34589
|
-
return
|
|
34718
|
+
return createHash13("sha256").update(bytes.subarray(0, length)).digest("base64url");
|
|
34590
34719
|
}
|
|
34591
34720
|
function fullDigest(snapshot) {
|
|
34592
34721
|
const key = `${snapshot.fileKey}\0${snapshot.bytes.length}`;
|
|
@@ -34671,7 +34800,7 @@ function emptyTranscriptPage(source) {
|
|
|
34671
34800
|
beforeCursor: null,
|
|
34672
34801
|
hasEarlier: false,
|
|
34673
34802
|
reachedTurnBoundary: true,
|
|
34674
|
-
transcriptKey:
|
|
34803
|
+
transcriptKey: createHash13("sha256").update(keySeed).digest("base64url").slice(0, 32)
|
|
34675
34804
|
};
|
|
34676
34805
|
}
|
|
34677
34806
|
function readLatestThreadTranscriptPage(project, storage, slug, backendFor) {
|
|
@@ -34738,7 +34867,7 @@ function readEarlierThreadTranscriptPage(project, storage, slug, cursor, backend
|
|
|
34738
34867
|
}
|
|
34739
34868
|
function readCodexTranscriptFile(absPath, nativeId = absPath) {
|
|
34740
34869
|
try {
|
|
34741
|
-
return parseCodexTranscript(
|
|
34870
|
+
return parseCodexTranscript(readFileSync17(absPath, "utf8"), `codex:${nativeId}`);
|
|
34742
34871
|
} catch {
|
|
34743
34872
|
return [];
|
|
34744
34873
|
}
|
|
@@ -34815,8 +34944,8 @@ function projectTranscriptPageAgentLifecycles(page, lookup) {
|
|
|
34815
34944
|
}
|
|
34816
34945
|
function readTranscriptFile(absPath) {
|
|
34817
34946
|
try {
|
|
34818
|
-
const pathKey =
|
|
34819
|
-
return parseTranscript(
|
|
34947
|
+
const pathKey = createHash13("sha256").update(absPath).digest("base64url").slice(0, 16);
|
|
34948
|
+
return parseTranscript(readFileSync17(absPath, "utf8"), `claude-file:${pathKey}`);
|
|
34820
34949
|
} catch {
|
|
34821
34950
|
return [];
|
|
34822
34951
|
}
|
|
@@ -34858,7 +34987,7 @@ var init_transcript = __esm({
|
|
|
34858
34987
|
"image/gif": "gif",
|
|
34859
34988
|
"image/webp": "webp"
|
|
34860
34989
|
};
|
|
34861
|
-
SCREENSHOT_CACHE_DIR =
|
|
34990
|
+
SCREENSHOT_CACHE_DIR = join29(tmpdir4(), "frizz-tool-images");
|
|
34862
34991
|
SCREENSHOT_CACHE_MAX = 200;
|
|
34863
34992
|
SCREENSHOT_MAX_BASE64 = 32e6;
|
|
34864
34993
|
screenshotTmpSeq = 0;
|
|
@@ -34910,8 +35039,8 @@ var init_open_external = __esm({
|
|
|
34910
35039
|
// packages/server/src/local-file.ts
|
|
34911
35040
|
import { spawn as spawn6 } from "node:child_process";
|
|
34912
35041
|
import { realpathSync as realpathSync7, statSync as statSync15 } from "node:fs";
|
|
34913
|
-
import { homedir as
|
|
34914
|
-
import { isAbsolute as isAbsolute3, join as
|
|
35042
|
+
import { homedir as homedir13 } from "node:os";
|
|
35043
|
+
import { isAbsolute as isAbsolute3, join as join30, resolve as resolve8, sep } from "node:path";
|
|
34915
35044
|
function isUnder(real, root) {
|
|
34916
35045
|
let rootReal;
|
|
34917
35046
|
try {
|
|
@@ -34938,10 +35067,10 @@ function resolveLocalFile(rawPath, roots) {
|
|
|
34938
35067
|
}
|
|
34939
35068
|
return real;
|
|
34940
35069
|
}
|
|
34941
|
-
function resolveOpenableFile(raw2, projectDir, roots, home =
|
|
35070
|
+
function resolveOpenableFile(raw2, projectDir, roots, home = homedir13()) {
|
|
34942
35071
|
const trimmed = raw2.trim().replace(/:\d+(?::\d+)?$/, "");
|
|
34943
35072
|
if (!trimmed) return null;
|
|
34944
|
-
const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ?
|
|
35073
|
+
const abs = trimmed === "~" ? home : trimmed.startsWith("~/") ? join30(home, trimmed.slice(2)) : isAbsolute3(trimmed) ? trimmed : resolve8(projectDir, trimmed);
|
|
34945
35074
|
try {
|
|
34946
35075
|
return resolveLocalFile(abs, roots);
|
|
34947
35076
|
} catch {
|
|
@@ -35007,7 +35136,7 @@ var init_account_actions = __esm({
|
|
|
35007
35136
|
});
|
|
35008
35137
|
|
|
35009
35138
|
// packages/server/src/awaiting.ts
|
|
35010
|
-
import { createHash as
|
|
35139
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
35011
35140
|
function parsePrRef2(value) {
|
|
35012
35141
|
const m = value.trim().match(PR_REF_RE2);
|
|
35013
35142
|
if (!m) return void 0;
|
|
@@ -35022,7 +35151,7 @@ function isActionableAwaitingHint(hint) {
|
|
|
35022
35151
|
return false;
|
|
35023
35152
|
}
|
|
35024
35153
|
function awaitingFenceIdentity(hint, fenceAt) {
|
|
35025
|
-
return
|
|
35154
|
+
return createHash14("sha256").update(fenceAt).update("\0").update(hint.kind).update("\0").update(hint.value).digest("hex");
|
|
35026
35155
|
}
|
|
35027
35156
|
var PR_REF_RE2;
|
|
35028
35157
|
var init_awaiting = __esm({
|
|
@@ -35109,11 +35238,11 @@ var init_external_terminal = __esm({
|
|
|
35109
35238
|
});
|
|
35110
35239
|
|
|
35111
35240
|
// packages/server/src/background-shell-output.ts
|
|
35112
|
-
import { closeSync as
|
|
35241
|
+
import { closeSync as closeSync12, fstatSync as fstatSync5, openSync as openSync13, readSync as readSync7 } from "node:fs";
|
|
35113
35242
|
function readBackgroundShellOutput(path, maxBytes = OUTPUT_TAIL_BYTES) {
|
|
35114
35243
|
let fd;
|
|
35115
35244
|
try {
|
|
35116
|
-
fd =
|
|
35245
|
+
fd = openSync13(path, "r");
|
|
35117
35246
|
const size = fstatSync5(fd).size;
|
|
35118
35247
|
const length = Math.min(size, maxBytes);
|
|
35119
35248
|
const offset = Math.max(0, size - length);
|
|
@@ -35129,13 +35258,13 @@ function readBackgroundShellOutput(path, maxBytes = OUTPUT_TAIL_BYTES) {
|
|
|
35129
35258
|
} catch {
|
|
35130
35259
|
return { output: "", truncated: false };
|
|
35131
35260
|
} finally {
|
|
35132
|
-
if (fd !== void 0)
|
|
35261
|
+
if (fd !== void 0) closeSync12(fd);
|
|
35133
35262
|
}
|
|
35134
35263
|
}
|
|
35135
35264
|
function backgroundShellLineCount(path) {
|
|
35136
35265
|
let fd;
|
|
35137
35266
|
try {
|
|
35138
|
-
fd =
|
|
35267
|
+
fd = openSync13(path, "r");
|
|
35139
35268
|
const stat2 = fstatSync5(fd);
|
|
35140
35269
|
const size = stat2.size;
|
|
35141
35270
|
let state = scans.get(path);
|
|
@@ -35174,7 +35303,7 @@ function backgroundShellLineCount(path) {
|
|
|
35174
35303
|
} catch {
|
|
35175
35304
|
return void 0;
|
|
35176
35305
|
} finally {
|
|
35177
|
-
if (fd !== void 0)
|
|
35306
|
+
if (fd !== void 0) closeSync12(fd);
|
|
35178
35307
|
}
|
|
35179
35308
|
}
|
|
35180
35309
|
var OUTPUT_TAIL_BYTES, SCAN_CHUNK_BYTES, SCAN_CEILING_BYTES, SCAN_CACHE_LIMIT, ANSI_ESCAPE_RE, scans;
|
|
@@ -35191,8 +35320,8 @@ var init_background_shell_output = __esm({
|
|
|
35191
35320
|
});
|
|
35192
35321
|
|
|
35193
35322
|
// packages/server/src/router.ts
|
|
35194
|
-
import { readFileSync as
|
|
35195
|
-
import { join as
|
|
35323
|
+
import { readFileSync as readFileSync18 } from "node:fs";
|
|
35324
|
+
import { join as join31 } from "node:path";
|
|
35196
35325
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
35197
35326
|
function validateGithubDispatchProfile(input) {
|
|
35198
35327
|
validateThreadProfile(input.backend, input.model, input.effort);
|
|
@@ -35328,7 +35457,7 @@ async function stopAndForgetRegisteredRuntime(storage, row, runtime = cachedLive
|
|
|
35328
35457
|
return forgotten;
|
|
35329
35458
|
}
|
|
35330
35459
|
function createRouter(ctx) {
|
|
35331
|
-
const frizzDir =
|
|
35460
|
+
const frizzDir = join31(ctx.project.dir, ".frizz");
|
|
35332
35461
|
const openRoots = openableFileRoots(ctx.project);
|
|
35333
35462
|
function isAutoTitledSession(slug) {
|
|
35334
35463
|
return ctx.storage.getSession(slug)?.title_auto === 1;
|
|
@@ -36445,7 +36574,7 @@ function createRouter(ctx) {
|
|
|
36445
36574
|
const row = ctx.storage.getSession(input.slug);
|
|
36446
36575
|
if (!row) return { markdown: "" };
|
|
36447
36576
|
try {
|
|
36448
|
-
return { markdown:
|
|
36577
|
+
return { markdown: readFileSync18(join31(ctx.project.dir, scratchpadRelPath(row.session_id)), "utf8") };
|
|
36449
36578
|
} catch {
|
|
36450
36579
|
return { markdown: "" };
|
|
36451
36580
|
}
|
|
@@ -36980,7 +37109,7 @@ var init_local_origin = __esm({
|
|
|
36980
37109
|
});
|
|
36981
37110
|
|
|
36982
37111
|
// packages/server/src/local-image.ts
|
|
36983
|
-
import { readFileSync as
|
|
37112
|
+
import { readFileSync as readFileSync19, realpathSync as realpathSync8, statSync as statSync16 } from "node:fs";
|
|
36984
37113
|
import { extname, isAbsolute as isAbsolute4 } from "node:path";
|
|
36985
37114
|
function resolveLocalImage(rawPath) {
|
|
36986
37115
|
if (!rawPath || !isAbsolute4(rawPath)) return { status: 400 };
|
|
@@ -36994,7 +37123,7 @@ function resolveLocalImage(rawPath) {
|
|
|
36994
37123
|
}
|
|
36995
37124
|
try {
|
|
36996
37125
|
if (!statSync16(real).isFile()) return { status: 404 };
|
|
36997
|
-
return { status: 200, contentType, body:
|
|
37126
|
+
return { status: 200, contentType, body: readFileSync19(real) };
|
|
36998
37127
|
} catch {
|
|
36999
37128
|
return { status: 404 };
|
|
37000
37129
|
}
|
|
@@ -37014,8 +37143,8 @@ var init_local_image = __esm({
|
|
|
37014
37143
|
});
|
|
37015
37144
|
|
|
37016
37145
|
// packages/server/src/local-visualization.ts
|
|
37017
|
-
import { readdirSync as readdirSync11, readFileSync as
|
|
37018
|
-
import { join as
|
|
37146
|
+
import { readdirSync as readdirSync11, readFileSync as readFileSync20, realpathSync as realpathSync9, statSync as statSync17 } from "node:fs";
|
|
37147
|
+
import { join as join32, sep as sep2 } from "node:path";
|
|
37019
37148
|
function children(path, pattern) {
|
|
37020
37149
|
try {
|
|
37021
37150
|
return readdirSync11(path, { withFileTypes: true }).filter((entry) => entry.isDirectory() && pattern.test(entry.name)).map((entry) => entry.name).sort().reverse();
|
|
@@ -37027,7 +37156,7 @@ function isUnder2(path, root) {
|
|
|
37027
37156
|
return path === root || path.startsWith(root.endsWith(sep2) ? root : root + sep2);
|
|
37028
37157
|
}
|
|
37029
37158
|
function resolveFragment(projectDir, sessionId, file) {
|
|
37030
|
-
const base =
|
|
37159
|
+
const base = join32(projectDir, ".codex", "visualizations");
|
|
37031
37160
|
let projectReal;
|
|
37032
37161
|
let baseReal;
|
|
37033
37162
|
try {
|
|
@@ -37038,12 +37167,12 @@ function resolveFragment(projectDir, sessionId, file) {
|
|
|
37038
37167
|
}
|
|
37039
37168
|
if (!isUnder2(baseReal, projectReal)) return null;
|
|
37040
37169
|
for (const year of children(base, YEAR_PART)) {
|
|
37041
|
-
const yearDir =
|
|
37170
|
+
const yearDir = join32(base, year);
|
|
37042
37171
|
for (const month of children(yearDir, DATE_PART)) {
|
|
37043
|
-
const monthDir =
|
|
37172
|
+
const monthDir = join32(yearDir, month);
|
|
37044
37173
|
for (const day of children(monthDir, DATE_PART)) {
|
|
37045
|
-
const sessionRoot =
|
|
37046
|
-
const candidate =
|
|
37174
|
+
const sessionRoot = join32(baseReal, year, month, day, sessionId);
|
|
37175
|
+
const candidate = join32(monthDir, day, sessionId, file);
|
|
37047
37176
|
try {
|
|
37048
37177
|
const real = realpathSync9(candidate);
|
|
37049
37178
|
if (isUnder2(real, sessionRoot) && statSync17(real).isFile()) return real;
|
|
@@ -37129,7 +37258,7 @@ function resolveLocalVisualization(projectDir, sessionId, file) {
|
|
|
37129
37258
|
try {
|
|
37130
37259
|
const size = statSync17(path).size;
|
|
37131
37260
|
if (size > MAX_FRAGMENT_BYTES) return { status: 413 };
|
|
37132
|
-
fragment =
|
|
37261
|
+
fragment = readFileSync20(path, "utf8");
|
|
37133
37262
|
} catch {
|
|
37134
37263
|
return { status: 404 };
|
|
37135
37264
|
}
|
|
@@ -37171,8 +37300,8 @@ var init_local_visualization = __esm({
|
|
|
37171
37300
|
});
|
|
37172
37301
|
|
|
37173
37302
|
// packages/server/src/app.ts
|
|
37174
|
-
import { mkdirSync as
|
|
37175
|
-
import { join as
|
|
37303
|
+
import { mkdirSync as mkdirSync14, writeFileSync as writeFileSync10 } from "node:fs";
|
|
37304
|
+
import { join as join33 } from "node:path";
|
|
37176
37305
|
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
37177
37306
|
function createApp(ctx, options = {}) {
|
|
37178
37307
|
const app = new Hono2();
|
|
@@ -37249,11 +37378,11 @@ function createApp(ctx, options = {}) {
|
|
|
37249
37378
|
if (typeof body.data !== "string" || body.data.length > ATTACHMENT_MAX_BASE64_CHARS) return c.json({ error: "bad payload" }, 400);
|
|
37250
37379
|
const ext = `.${attachmentExtension(name)}`;
|
|
37251
37380
|
const buf = Buffer.from(body.data, "base64");
|
|
37252
|
-
const dir =
|
|
37253
|
-
|
|
37381
|
+
const dir = join33(ctx.project.stateDir, "attachments");
|
|
37382
|
+
mkdirSync14(dir, { recursive: true });
|
|
37254
37383
|
const base = name.replace(/\.[^.]+$/, "").replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 40) || "file";
|
|
37255
|
-
const path =
|
|
37256
|
-
|
|
37384
|
+
const path = join33(dir, `${Date.now()}-${randomUUID16().slice(0, 8)}-${base}${ext}`);
|
|
37385
|
+
writeFileSync10(path, buf);
|
|
37257
37386
|
return c.json({ path });
|
|
37258
37387
|
});
|
|
37259
37388
|
app.get(
|
|
@@ -37280,10 +37409,10 @@ function createApp(ctx, options = {}) {
|
|
|
37280
37409
|
const heartbeat = setInterval(() => void stream2.writeSSE({ event: "heartbeat", data: "" }).catch(() => {
|
|
37281
37410
|
}), 1e4);
|
|
37282
37411
|
await new Promise(
|
|
37283
|
-
(
|
|
37412
|
+
(resolve10) => stream2.onAbort(() => {
|
|
37284
37413
|
unsubscribe();
|
|
37285
37414
|
clearInterval(heartbeat);
|
|
37286
|
-
|
|
37415
|
+
resolve10();
|
|
37287
37416
|
})
|
|
37288
37417
|
);
|
|
37289
37418
|
})
|
|
@@ -37664,13 +37793,13 @@ function createTerminalServer(deps = {}) {
|
|
|
37664
37793
|
}
|
|
37665
37794
|
for (const viewer of [...viewers]) viewer.shutdown();
|
|
37666
37795
|
let drainTimer;
|
|
37667
|
-
const boundedServerDrain = new Promise((
|
|
37796
|
+
const boundedServerDrain = new Promise((resolve10) => {
|
|
37668
37797
|
let resolved = false;
|
|
37669
37798
|
const finish = () => {
|
|
37670
37799
|
if (resolved) return;
|
|
37671
37800
|
resolved = true;
|
|
37672
37801
|
clearTimeout(drainTimer);
|
|
37673
|
-
|
|
37802
|
+
resolve10();
|
|
37674
37803
|
};
|
|
37675
37804
|
drainTimer = setTimeout(finish, shutdownGraceMs);
|
|
37676
37805
|
try {
|
|
@@ -37710,7 +37839,7 @@ var init_terminal = __esm({
|
|
|
37710
37839
|
});
|
|
37711
37840
|
|
|
37712
37841
|
// packages/server/src/app-socket.ts
|
|
37713
|
-
import { createHash as
|
|
37842
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
37714
37843
|
function isWsPath(url) {
|
|
37715
37844
|
return (url ?? "").split("?")[0] === WS_PATH;
|
|
37716
37845
|
}
|
|
@@ -37845,7 +37974,7 @@ function createAppSocketServer(deps) {
|
|
|
37845
37974
|
sendEncoded(ws, frame, false);
|
|
37846
37975
|
}
|
|
37847
37976
|
function frameSignature(frame) {
|
|
37848
|
-
return
|
|
37977
|
+
return createHash15("sha256").update(frame.text).digest("base64url");
|
|
37849
37978
|
}
|
|
37850
37979
|
const globalReadTimes = [];
|
|
37851
37980
|
const originReadTimes = /* @__PURE__ */ new Map();
|
|
@@ -38343,13 +38472,13 @@ function createAppSocketServer(deps) {
|
|
|
38343
38472
|
clearTranscriptSnapshots();
|
|
38344
38473
|
globalReadTimes.length = 0;
|
|
38345
38474
|
originReadTimes.clear();
|
|
38346
|
-
const socketDrains = [...wss.clients].map((ws) => new Promise((
|
|
38347
|
-
if (ws.readyState === ws.CLOSED) return
|
|
38348
|
-
ws.once("close", () =>
|
|
38475
|
+
const socketDrains = [...wss.clients].map((ws) => new Promise((resolve10) => {
|
|
38476
|
+
if (ws.readyState === ws.CLOSED) return resolve10();
|
|
38477
|
+
ws.once("close", () => resolve10());
|
|
38349
38478
|
try {
|
|
38350
38479
|
ws.terminate();
|
|
38351
38480
|
} catch {
|
|
38352
|
-
|
|
38481
|
+
resolve10();
|
|
38353
38482
|
}
|
|
38354
38483
|
}));
|
|
38355
38484
|
lastSig.clear();
|
|
@@ -38475,10 +38604,10 @@ var init_app_socket = __esm({
|
|
|
38475
38604
|
});
|
|
38476
38605
|
|
|
38477
38606
|
// packages/server/src/boot-progress.ts
|
|
38478
|
-
import { mkdirSync as
|
|
38479
|
-
import { basename as basename8, dirname as
|
|
38607
|
+
import { mkdirSync as mkdirSync15, readFileSync as readFileSync21, renameSync as renameSync9, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
38608
|
+
import { basename as basename8, dirname as dirname10, join as join34 } from "node:path";
|
|
38480
38609
|
function bootProgressPath(stateDir) {
|
|
38481
|
-
return
|
|
38610
|
+
return join34(stateDir, BOOT_PROGRESS_NAME);
|
|
38482
38611
|
}
|
|
38483
38612
|
function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
38484
38613
|
if (!stateDir) {
|
|
@@ -38498,18 +38627,18 @@ function createBootProgressPublisher(stateDir, minIntervalMs = 200) {
|
|
|
38498
38627
|
lastAt = now;
|
|
38499
38628
|
step++;
|
|
38500
38629
|
try {
|
|
38501
|
-
|
|
38502
|
-
const temp =
|
|
38503
|
-
|
|
38630
|
+
mkdirSync15(dirname10(path), { recursive: true, mode: 448 });
|
|
38631
|
+
const temp = join34(dirname10(path), `.${basename8(path)}.${process.pid}.tmp`);
|
|
38632
|
+
writeFileSync11(temp, `${JSON.stringify({ pid: process.pid, step, phase, at: new Date(now).toISOString() })}
|
|
38504
38633
|
`, "utf8");
|
|
38505
|
-
|
|
38634
|
+
renameSync9(temp, path);
|
|
38506
38635
|
} catch {
|
|
38507
38636
|
}
|
|
38508
38637
|
};
|
|
38509
38638
|
return Object.assign(write, {
|
|
38510
38639
|
done: () => {
|
|
38511
38640
|
try {
|
|
38512
|
-
|
|
38641
|
+
rmSync7(path, { force: true });
|
|
38513
38642
|
} catch {
|
|
38514
38643
|
}
|
|
38515
38644
|
}
|
|
@@ -38534,8 +38663,8 @@ __export(index_exports, {
|
|
|
38534
38663
|
startServer: () => startServer
|
|
38535
38664
|
});
|
|
38536
38665
|
import { createServer } from "node:http";
|
|
38537
|
-
import { readFileSync as
|
|
38538
|
-
import { join as
|
|
38666
|
+
import { readFileSync as readFileSync22, existsSync as existsSync12 } from "node:fs";
|
|
38667
|
+
import { join as join35, resolve as resolve9, extname as extname2, normalize } from "node:path";
|
|
38539
38668
|
async function pipeToApp(app, req, res, port2, controller) {
|
|
38540
38669
|
const url = `http://127.0.0.1:${port2}${req.url ?? "/"}`;
|
|
38541
38670
|
res.on("close", () => {
|
|
@@ -38604,11 +38733,11 @@ function createShutdownSignalHandler(options) {
|
|
|
38604
38733
|
}
|
|
38605
38734
|
function serveStatic(distDir, req, res) {
|
|
38606
38735
|
const rel = normalize((req.url ?? "/").split("?")[0]).replace(/^(\.\.[/\\])+/, "");
|
|
38607
|
-
let file =
|
|
38608
|
-
if (!file.startsWith(distDir)) file =
|
|
38609
|
-
if (!
|
|
38736
|
+
let file = join35(distDir, rel === "/" ? "index.html" : rel);
|
|
38737
|
+
if (!file.startsWith(distDir)) file = join35(distDir, "index.html");
|
|
38738
|
+
if (!existsSync12(file)) file = join35(distDir, "index.html");
|
|
38610
38739
|
try {
|
|
38611
|
-
const body =
|
|
38740
|
+
const body = readFileSync22(file);
|
|
38612
38741
|
res.writeHead(200, { "content-type": MIME[extname2(file)] ?? "application/octet-stream" });
|
|
38613
38742
|
res.end(body);
|
|
38614
38743
|
} catch {
|
|
@@ -38893,9 +39022,9 @@ async function startServer(opts = {}) {
|
|
|
38893
39022
|
} else {
|
|
38894
39023
|
await phase("wake scheduler", () => void 0);
|
|
38895
39024
|
}
|
|
38896
|
-
statusPath =
|
|
38897
|
-
const webRoot =
|
|
38898
|
-
const distDir = opts.webDistDir ?
|
|
39025
|
+
statusPath = join35(ctx.project.stateDir, "server.lock");
|
|
39026
|
+
const webRoot = resolve9(import.meta.dirname, "..", "..", "web");
|
|
39027
|
+
const distDir = opts.webDistDir ? resolve9(opts.webDistDir) : join35(webRoot, "dist");
|
|
38899
39028
|
startupPhase = "Vite";
|
|
38900
39029
|
if (opts.dev) {
|
|
38901
39030
|
try {
|
|
@@ -38939,7 +39068,7 @@ async function startServer(opts = {}) {
|
|
|
38939
39068
|
if (vite) {
|
|
38940
39069
|
vite.middlewares(req, res, () => {
|
|
38941
39070
|
try {
|
|
38942
|
-
const html =
|
|
39071
|
+
const html = readFileSync22(join35(webRoot, "index.html"), "utf8");
|
|
38943
39072
|
void vite.transformIndexHtml(url, html).then((out) => {
|
|
38944
39073
|
res.writeHead(200, { "content-type": "text/html" });
|
|
38945
39074
|
res.end(out);
|
|
@@ -38951,7 +39080,7 @@ async function startServer(opts = {}) {
|
|
|
38951
39080
|
});
|
|
38952
39081
|
return;
|
|
38953
39082
|
}
|
|
38954
|
-
if (
|
|
39083
|
+
if (existsSync12(distDir)) {
|
|
38955
39084
|
serveStatic(distDir, req, res);
|
|
38956
39085
|
return;
|
|
38957
39086
|
}
|
|
@@ -39119,8 +39248,8 @@ init_project();
|
|
|
39119
39248
|
init_project_launch();
|
|
39120
39249
|
init_shutdown();
|
|
39121
39250
|
init_logging();
|
|
39122
|
-
import { existsSync as
|
|
39123
|
-
import { join as
|
|
39251
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
39252
|
+
import { join as join36 } from "node:path";
|
|
39124
39253
|
process.on("uncaughtException", (error) => {
|
|
39125
39254
|
log.error("dev-child", `uncaught exception: ${error instanceof Error ? error.stack ?? error.message : error}`);
|
|
39126
39255
|
process.exit(1);
|
|
@@ -39158,9 +39287,9 @@ try {
|
|
|
39158
39287
|
["FRIZZ_SCRIPTS_DIR", process.env.FRIZZ_SCRIPTS_DIR, "index.mjs"],
|
|
39159
39288
|
["FRIZZ_WORKER_PLUGIN_DIR", process.env.FRIZZ_WORKER_PLUGIN_DIR, ".claude-plugin/plugin.json"]
|
|
39160
39289
|
];
|
|
39161
|
-
if (!
|
|
39290
|
+
if (!existsSync13(stableWebDist)) throw new Error("stable artifact launch is missing its verified web directory");
|
|
39162
39291
|
for (const [name, directory, requiredFile] of required) {
|
|
39163
|
-
if (!directory || !
|
|
39292
|
+
if (!directory || !existsSync13(join36(directory, requiredFile)))
|
|
39164
39293
|
throw new Error(`stable artifact launch is missing verified ${name}`);
|
|
39165
39294
|
}
|
|
39166
39295
|
}
|