@deeplake/hivemind 0.7.17 → 0.7.18

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.
@@ -53,9 +53,9 @@ var init_index_marker_store = __esm({
53
53
  });
54
54
 
55
55
  // dist/src/hooks/codex/stop.js
56
- import { readFileSync as readFileSync7, existsSync as existsSync8 } from "node:fs";
56
+ import { readFileSync as readFileSync7, existsSync as existsSync9 } from "node:fs";
57
57
  import { fileURLToPath as fileURLToPath3 } from "node:url";
58
- import { dirname as dirname3, join as join13 } from "node:path";
58
+ import { dirname as dirname3, join as join14 } from "node:path";
59
59
 
60
60
  // dist/src/utils/stdin.js
61
61
  function readStdin() {
@@ -679,14 +679,14 @@ function bundleDirFromImportMeta(importMetaUrl) {
679
679
  return dirname(fileURLToPath(importMetaUrl));
680
680
  }
681
681
 
682
- // dist/src/skilify/spawn-skilify-worker.js
682
+ // dist/src/skillify/spawn-skillify-worker.js
683
683
  import { spawn as spawn2 } from "node:child_process";
684
684
  import { fileURLToPath as fileURLToPath2 } from "node:url";
685
685
  import { dirname as dirname2, join as join7 } from "node:path";
686
686
  import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
687
687
  import { homedir as homedir5, tmpdir as tmpdir3 } from "node:os";
688
688
 
689
- // dist/src/skilify/gate-runner.js
689
+ // dist/src/skillify/gate-runner.js
690
690
  import { execFileSync } from "node:child_process";
691
691
  import { existsSync as existsSync3 } from "node:fs";
692
692
  import { homedir as homedir4 } from "node:os";
@@ -717,20 +717,20 @@ function findAgentBin(agent) {
717
717
  }
718
718
  }
719
719
 
720
- // dist/src/skilify/spawn-skilify-worker.js
720
+ // dist/src/skillify/spawn-skillify-worker.js
721
721
  var HOME2 = homedir5();
722
- var SKILIFY_LOG = join7(HOME2, ".claude", "hooks", "skilify.log");
723
- function skilifyLog(msg) {
722
+ var SKILLIFY_LOG = join7(HOME2, ".claude", "hooks", "skillify.log");
723
+ function skillifyLog(msg) {
724
724
  try {
725
- mkdirSync4(dirname2(SKILIFY_LOG), { recursive: true });
726
- appendFileSync3(SKILIFY_LOG, `[${utcTimestamp()}] ${msg}
725
+ mkdirSync4(dirname2(SKILLIFY_LOG), { recursive: true });
726
+ appendFileSync3(SKILLIFY_LOG, `[${utcTimestamp()}] ${msg}
727
727
  `);
728
728
  } catch {
729
729
  }
730
730
  }
731
- function spawnSkilifyWorker(opts) {
731
+ function spawnSkillifyWorker(opts) {
732
732
  const { config, cwd, projectKey, project, bundleDir, agent, scopeConfig, currentSessionId, reason } = opts;
733
- const tmpDir = join7(tmpdir3(), `deeplake-skilify-${projectKey}-${Date.now()}`);
733
+ const tmpDir = join7(tmpdir3(), `deeplake-skillify-${projectKey}-${Date.now()}`);
734
734
  mkdirSync4(tmpDir, { recursive: true, mode: 448 });
735
735
  const gateBin = findAgentBin(agent);
736
736
  const configFile = join7(tmpDir, "config.json");
@@ -756,40 +756,72 @@ function spawnSkilifyWorker(opts) {
756
756
  hermesModel: process.env.HIVEMIND_HERMES_MODEL,
757
757
  piProvider: process.env.HIVEMIND_PI_PROVIDER,
758
758
  piModel: process.env.HIVEMIND_PI_MODEL,
759
- skilifyLog: SKILIFY_LOG,
759
+ skillifyLog: SKILLIFY_LOG,
760
760
  currentSessionId
761
761
  }), { mode: 384 });
762
762
  try {
763
763
  chmodSync(configFile, 384);
764
764
  } catch {
765
765
  }
766
- skilifyLog(`${reason}: spawning skilify worker for project=${project} key=${projectKey}`);
767
- const workerPath = join7(bundleDir, "skilify-worker.js");
766
+ skillifyLog(`${reason}: spawning skillify worker for project=${project} key=${projectKey}`);
767
+ const workerPath = join7(bundleDir, "skillify-worker.js");
768
768
  spawn2("nohup", ["node", workerPath, configFile], {
769
769
  detached: true,
770
770
  stdio: ["ignore", "ignore", "ignore"]
771
771
  }).unref();
772
- skilifyLog(`${reason}: spawned skilify worker for ${projectKey}`);
772
+ skillifyLog(`${reason}: spawned skillify worker for ${projectKey}`);
773
773
  }
774
774
 
775
- // dist/src/skilify/state.js
776
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, writeSync, mkdirSync as mkdirSync5, renameSync, existsSync as existsSync4, unlinkSync, openSync, closeSync } from "node:fs";
775
+ // dist/src/skillify/state.js
776
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync4, writeSync, mkdirSync as mkdirSync5, renameSync as renameSync2, existsSync as existsSync5, unlinkSync, openSync, closeSync } from "node:fs";
777
777
  import { execSync as execSync2 } from "node:child_process";
778
- import { homedir as homedir6 } from "node:os";
778
+ import { homedir as homedir7 } from "node:os";
779
779
  import { createHash } from "node:crypto";
780
- import { join as join8, basename } from "node:path";
781
- var dlog = (msg) => log("skilify-state", msg);
782
- var STATE_DIR = join8(homedir6(), ".deeplake", "state", "skilify");
780
+ import { join as join9, basename } from "node:path";
781
+
782
+ // dist/src/skillify/legacy-migration.js
783
+ import { existsSync as existsSync4, renameSync } from "node:fs";
784
+ import { homedir as homedir6 } from "node:os";
785
+ import { join as join8 } from "node:path";
786
+ var dlog = (msg) => log("skillify-migrate", msg);
787
+ var attempted = false;
788
+ function migrateLegacyStateDir() {
789
+ if (attempted)
790
+ return;
791
+ attempted = true;
792
+ const root = join8(homedir6(), ".deeplake", "state");
793
+ const legacy = join8(root, "skilify");
794
+ const current = join8(root, "skillify");
795
+ if (!existsSync4(legacy))
796
+ return;
797
+ if (existsSync4(current))
798
+ return;
799
+ try {
800
+ renameSync(legacy, current);
801
+ dlog(`migrated ${legacy} -> ${current}`);
802
+ } catch (err) {
803
+ const code = err.code;
804
+ if (code === "EXDEV" || code === "EPERM") {
805
+ dlog(`migration failed (${code}); leaving legacy dir in place`);
806
+ return;
807
+ }
808
+ throw err;
809
+ }
810
+ }
811
+
812
+ // dist/src/skillify/state.js
813
+ var dlog2 = (msg) => log("skillify-state", msg);
814
+ var STATE_DIR = join9(homedir7(), ".deeplake", "state", "skillify");
783
815
  var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
784
816
  var TRIGGER_THRESHOLD = (() => {
785
- const n = Number(process.env.HIVEMIND_SKILIFY_EVERY_N_TURNS ?? "");
817
+ const n = Number(process.env.HIVEMIND_SKILLIFY_EVERY_N_TURNS ?? "");
786
818
  return Number.isInteger(n) && n > 0 ? n : 20;
787
819
  })();
788
820
  function statePath(projectKey) {
789
- return join8(STATE_DIR, `${projectKey}.json`);
821
+ return join9(STATE_DIR, `${projectKey}.json`);
790
822
  }
791
823
  function lockPath(projectKey) {
792
- return join8(STATE_DIR, `${projectKey}.lock`);
824
+ return join9(STATE_DIR, `${projectKey}.lock`);
793
825
  }
794
826
  function deriveProjectKey(cwd) {
795
827
  const project = basename(cwd) || "unknown";
@@ -807,8 +839,9 @@ function deriveProjectKey(cwd) {
807
839
  return { key, project };
808
840
  }
809
841
  function readState(projectKey) {
842
+ migrateLegacyStateDir();
810
843
  const p = statePath(projectKey);
811
- if (!existsSync4(p))
844
+ if (!existsSync5(p))
812
845
  return null;
813
846
  try {
814
847
  return JSON.parse(readFileSync3(p, "utf-8"));
@@ -817,13 +850,15 @@ function readState(projectKey) {
817
850
  }
818
851
  }
819
852
  function writeState(projectKey, state) {
853
+ migrateLegacyStateDir();
820
854
  mkdirSync5(STATE_DIR, { recursive: true });
821
855
  const p = statePath(projectKey);
822
856
  const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
823
857
  writeFileSync4(tmp, JSON.stringify(state, null, 2));
824
- renameSync(tmp, p);
858
+ renameSync2(tmp, p);
825
859
  }
826
860
  function withRmwLock(projectKey, fn) {
861
+ migrateLegacyStateDir();
827
862
  mkdirSync5(STATE_DIR, { recursive: true });
828
863
  const rmw = lockPath(projectKey) + ".rmw";
829
864
  const deadline = Date.now() + 2e3;
@@ -835,11 +870,11 @@ function withRmwLock(projectKey, fn) {
835
870
  if (e.code !== "EEXIST")
836
871
  throw e;
837
872
  if (Date.now() > deadline) {
838
- dlog(`rmw lock deadline exceeded for ${projectKey}, reclaiming stale lock`);
873
+ dlog2(`rmw lock deadline exceeded for ${projectKey}, reclaiming stale lock`);
839
874
  try {
840
875
  unlinkSync(rmw);
841
876
  } catch (unlinkErr) {
842
- dlog(`stale rmw lock unlink failed for ${projectKey}: ${unlinkErr.message}`);
877
+ dlog2(`stale rmw lock unlink failed for ${projectKey}: ${unlinkErr.message}`);
843
878
  }
844
879
  continue;
845
880
  }
@@ -853,7 +888,7 @@ function withRmwLock(projectKey, fn) {
853
888
  try {
854
889
  unlinkSync(rmw);
855
890
  } catch (unlinkErr) {
856
- dlog(`rmw lock cleanup failed for ${projectKey}: ${unlinkErr.message}`);
891
+ dlog2(`rmw lock cleanup failed for ${projectKey}: ${unlinkErr.message}`);
857
892
  }
858
893
  }
859
894
  }
@@ -866,20 +901,21 @@ function resetCounter(projectKey) {
866
901
  });
867
902
  }
868
903
  function tryAcquireWorkerLock(projectKey, maxAgeMs = 10 * 60 * 1e3) {
904
+ migrateLegacyStateDir();
869
905
  mkdirSync5(STATE_DIR, { recursive: true });
870
906
  const p = lockPath(projectKey);
871
- if (existsSync4(p)) {
907
+ if (existsSync5(p)) {
872
908
  try {
873
909
  const ageMs = Date.now() - parseInt(readFileSync3(p, "utf-8"), 10);
874
910
  if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
875
911
  return false;
876
912
  } catch (readErr) {
877
- dlog(`worker lock unreadable for ${projectKey}, treating as stale: ${readErr.message}`);
913
+ dlog2(`worker lock unreadable for ${projectKey}, treating as stale: ${readErr.message}`);
878
914
  }
879
915
  try {
880
916
  unlinkSync(p);
881
917
  } catch (unlinkErr) {
882
- dlog(`could not unlink stale worker lock for ${projectKey}: ${unlinkErr.message}`);
918
+ dlog2(`could not unlink stale worker lock for ${projectKey}: ${unlinkErr.message}`);
883
919
  return false;
884
920
  }
885
921
  }
@@ -903,15 +939,16 @@ function releaseWorkerLock(projectKey) {
903
939
  }
904
940
  }
905
941
 
906
- // dist/src/skilify/scope-config.js
907
- import { existsSync as existsSync5, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "node:fs";
908
- import { homedir as homedir7 } from "node:os";
909
- import { join as join9 } from "node:path";
910
- var STATE_DIR2 = join9(homedir7(), ".deeplake", "state", "skilify");
911
- var CONFIG_PATH = join9(STATE_DIR2, "config.json");
942
+ // dist/src/skillify/scope-config.js
943
+ import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "node:fs";
944
+ import { homedir as homedir8 } from "node:os";
945
+ import { join as join10 } from "node:path";
946
+ var STATE_DIR2 = join10(homedir8(), ".deeplake", "state", "skillify");
947
+ var CONFIG_PATH = join10(STATE_DIR2, "config.json");
912
948
  var DEFAULT = { scope: "me", team: [], install: "project" };
913
949
  function loadScopeConfig() {
914
- if (!existsSync5(CONFIG_PATH))
950
+ migrateLegacyStateDir();
951
+ if (!existsSync6(CONFIG_PATH))
915
952
  return DEFAULT;
916
953
  try {
917
954
  const raw = JSON.parse(readFileSync4(CONFIG_PATH, "utf-8"));
@@ -924,24 +961,24 @@ function loadScopeConfig() {
924
961
  }
925
962
  }
926
963
 
927
- // dist/src/skilify/triggers.js
964
+ // dist/src/skillify/triggers.js
928
965
  function forceSessionEndTrigger(opts) {
929
- if (process.env.HIVEMIND_SKILIFY_WORKER === "1")
966
+ if (process.env.HIVEMIND_SKILLIFY_WORKER === "1")
930
967
  return;
931
968
  if (!opts.cwd)
932
969
  return;
933
970
  try {
934
971
  const { key: projectKey, project } = deriveProjectKey(opts.cwd);
935
972
  if (!tryAcquireWorkerLock(projectKey)) {
936
- skilifyLog(`SessionEnd: skilify worker already running for ${projectKey}, skipping`);
973
+ skillifyLog(`SessionEnd: skillify worker already running for ${projectKey}, skipping`);
937
974
  return;
938
975
  }
939
976
  if (readState(projectKey)) {
940
977
  resetCounter(projectKey);
941
978
  }
942
- skilifyLog(`SessionEnd: spawning skilify worker for project=${project} agent=${opts.agent}`);
979
+ skillifyLog(`SessionEnd: spawning skillify worker for project=${project} agent=${opts.agent}`);
943
980
  try {
944
- spawnSkilifyWorker({
981
+ spawnSkillifyWorker({
945
982
  config: opts.config,
946
983
  cwd: opts.cwd,
947
984
  projectKey,
@@ -953,42 +990,42 @@ function forceSessionEndTrigger(opts) {
953
990
  reason: "SessionEnd"
954
991
  });
955
992
  } catch (e) {
956
- skilifyLog(`SessionEnd spawn failed: ${e?.message ?? e}`);
993
+ skillifyLog(`SessionEnd spawn failed: ${e?.message ?? e}`);
957
994
  try {
958
995
  releaseWorkerLock(projectKey);
959
996
  } catch {
960
997
  }
961
998
  }
962
999
  } catch (e) {
963
- skilifyLog(`SessionEnd trigger error: ${e?.message ?? e}`);
1000
+ skillifyLog(`SessionEnd trigger error: ${e?.message ?? e}`);
964
1001
  }
965
1002
  }
966
1003
 
967
1004
  // dist/src/hooks/summary-state.js
968
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync6, writeSync as writeSync2, mkdirSync as mkdirSync7, renameSync as renameSync2, existsSync as existsSync6, unlinkSync as unlinkSync2, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
969
- import { homedir as homedir8 } from "node:os";
970
- import { join as join10 } from "node:path";
971
- var dlog2 = (msg) => log("summary-state", msg);
972
- var STATE_DIR3 = join10(homedir8(), ".claude", "hooks", "summary-state");
1005
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync6, writeSync as writeSync2, mkdirSync as mkdirSync7, renameSync as renameSync3, existsSync as existsSync7, unlinkSync as unlinkSync2, openSync as openSync2, closeSync as closeSync2 } from "node:fs";
1006
+ import { homedir as homedir9 } from "node:os";
1007
+ import { join as join11 } from "node:path";
1008
+ var dlog3 = (msg) => log("summary-state", msg);
1009
+ var STATE_DIR3 = join11(homedir9(), ".claude", "hooks", "summary-state");
973
1010
  var YIELD_BUF2 = new Int32Array(new SharedArrayBuffer(4));
974
1011
  function lockPath2(sessionId) {
975
- return join10(STATE_DIR3, `${sessionId}.lock`);
1012
+ return join11(STATE_DIR3, `${sessionId}.lock`);
976
1013
  }
977
1014
  function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
978
1015
  mkdirSync7(STATE_DIR3, { recursive: true });
979
1016
  const p = lockPath2(sessionId);
980
- if (existsSync6(p)) {
1017
+ if (existsSync7(p)) {
981
1018
  try {
982
1019
  const ageMs = Date.now() - parseInt(readFileSync5(p, "utf-8"), 10);
983
1020
  if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
984
1021
  return false;
985
1022
  } catch (readErr) {
986
- dlog2(`lock file unreadable for ${sessionId}, treating as stale: ${readErr.message}`);
1023
+ dlog3(`lock file unreadable for ${sessionId}, treating as stale: ${readErr.message}`);
987
1024
  }
988
1025
  try {
989
1026
  unlinkSync2(p);
990
1027
  } catch (unlinkErr) {
991
- dlog2(`could not unlink stale lock for ${sessionId}: ${unlinkErr.message}`);
1028
+ dlog3(`could not unlink stale lock for ${sessionId}: ${unlinkErr.message}`);
992
1029
  return false;
993
1030
  }
994
1031
  }
@@ -1011,7 +1048,7 @@ function releaseLock(sessionId) {
1011
1048
  unlinkSync2(lockPath2(sessionId));
1012
1049
  } catch (e) {
1013
1050
  if (e?.code !== "ENOENT") {
1014
- dlog2(`releaseLock unlink failed for ${sessionId}: ${e.message}`);
1051
+ dlog3(`releaseLock unlink failed for ${sessionId}: ${e.message}`);
1015
1052
  }
1016
1053
  }
1017
1054
  }
@@ -1025,9 +1062,9 @@ function buildSessionPath(config, sessionId) {
1025
1062
  // dist/src/embeddings/client.js
1026
1063
  import { connect } from "node:net";
1027
1064
  import { spawn as spawn3 } from "node:child_process";
1028
- import { openSync as openSync3, closeSync as closeSync3, writeSync as writeSync3, unlinkSync as unlinkSync3, existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
1029
- import { homedir as homedir9 } from "node:os";
1030
- import { join as join11 } from "node:path";
1065
+ import { openSync as openSync3, closeSync as closeSync3, writeSync as writeSync3, unlinkSync as unlinkSync3, existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
1066
+ import { homedir as homedir10 } from "node:os";
1067
+ import { join as join12 } from "node:path";
1031
1068
 
1032
1069
  // dist/src/embeddings/protocol.js
1033
1070
  var DEFAULT_SOCKET_DIR = "/tmp";
@@ -1041,7 +1078,7 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
1041
1078
  }
1042
1079
 
1043
1080
  // dist/src/embeddings/client.js
1044
- var SHARED_DAEMON_PATH = join11(homedir9(), ".hivemind", "embed-deps", "embed-daemon.js");
1081
+ var SHARED_DAEMON_PATH = join12(homedir10(), ".hivemind", "embed-deps", "embed-daemon.js");
1045
1082
  var log3 = (m) => log("embed-client", m);
1046
1083
  function getUid() {
1047
1084
  const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
@@ -1061,7 +1098,7 @@ var EmbedClient = class {
1061
1098
  this.socketPath = socketPathFor(uid, dir);
1062
1099
  this.pidPath = pidPathFor(uid, dir);
1063
1100
  this.timeoutMs = opts.timeoutMs ?? DEFAULT_CLIENT_TIMEOUT_MS;
1064
- this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (existsSync7(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
1101
+ this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (existsSync8(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
1065
1102
  this.autoSpawn = opts.autoSpawn ?? true;
1066
1103
  this.spawnWaitMs = opts.spawnWaitMs ?? 5e3;
1067
1104
  }
@@ -1161,7 +1198,7 @@ var EmbedClient = class {
1161
1198
  return;
1162
1199
  }
1163
1200
  }
1164
- if (!this.daemonEntry || !existsSync7(this.daemonEntry)) {
1201
+ if (!this.daemonEntry || !existsSync8(this.daemonEntry)) {
1165
1202
  log3(`daemonEntry not configured or missing: ${this.daemonEntry}`);
1166
1203
  try {
1167
1204
  closeSync3(fd);
@@ -1204,7 +1241,7 @@ var EmbedClient = class {
1204
1241
  while (Date.now() < deadline) {
1205
1242
  await sleep2(delay);
1206
1243
  delay = Math.min(delay * 1.5, 300);
1207
- if (!existsSync7(this.socketPath))
1244
+ if (!existsSync8(this.socketPath))
1208
1245
  continue;
1209
1246
  try {
1210
1247
  return await this.connectOnce();
@@ -1265,8 +1302,8 @@ function embeddingSqlLiteral(vec) {
1265
1302
 
1266
1303
  // dist/src/embeddings/disable.js
1267
1304
  import { createRequire } from "node:module";
1268
- import { homedir as homedir10 } from "node:os";
1269
- import { join as join12 } from "node:path";
1305
+ import { homedir as homedir11 } from "node:os";
1306
+ import { join as join13 } from "node:path";
1270
1307
  import { pathToFileURL } from "node:url";
1271
1308
  var cachedStatus = null;
1272
1309
  function defaultResolveTransformers() {
@@ -1275,7 +1312,7 @@ function defaultResolveTransformers() {
1275
1312
  return;
1276
1313
  } catch {
1277
1314
  }
1278
- const sharedDir = join12(homedir10(), ".hivemind", "embed-deps");
1315
+ const sharedDir = join13(homedir11(), ".hivemind", "embed-deps");
1279
1316
  createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
1280
1317
  }
1281
1318
  var _resolve = defaultResolveTransformers;
@@ -1302,7 +1339,7 @@ function embeddingsDisabled() {
1302
1339
  // dist/src/hooks/codex/stop.js
1303
1340
  var log4 = (msg) => log("codex-stop", msg);
1304
1341
  function resolveEmbedDaemonPath() {
1305
- return join13(dirname3(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
1342
+ return join14(dirname3(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
1306
1343
  }
1307
1344
  var CAPTURE = process.env.HIVEMIND_CAPTURE !== "false";
1308
1345
  async function main() {
@@ -1326,7 +1363,7 @@ async function main() {
1326
1363
  if (input.transcript_path) {
1327
1364
  try {
1328
1365
  const transcriptPath = input.transcript_path;
1329
- if (existsSync8(transcriptPath)) {
1366
+ if (existsSync9(transcriptPath)) {
1330
1367
  const transcript = readFileSync7(transcriptPath, "utf-8");
1331
1368
  const lines = transcript.trim().split("\n").reverse();
1332
1369
  for (const line2 of lines) {