@deeplake/hivemind 0.7.4 → 0.7.11
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +97 -0
- package/bundle/cli.js +820 -20
- package/codex/bundle/capture.js +40 -10
- package/codex/bundle/commands/auth-login.js +84 -18
- package/codex/bundle/pre-tool-use.js +41 -11
- package/codex/bundle/session-start-setup.js +40 -10
- package/codex/bundle/session-start.js +27 -3
- package/codex/bundle/shell/deeplake-shell.js +41 -11
- package/codex/bundle/skilify-worker.js +907 -0
- package/codex/bundle/stop.js +373 -51
- package/cursor/bundle/capture.js +354 -13
- package/cursor/bundle/commands/auth-login.js +84 -18
- package/cursor/bundle/pre-tool-use.js +40 -10
- package/cursor/bundle/session-end.js +303 -6
- package/cursor/bundle/session-start.js +68 -14
- package/cursor/bundle/shell/deeplake-shell.js +41 -11
- package/cursor/bundle/skilify-worker.js +907 -0
- package/hermes/bundle/capture.js +354 -13
- package/hermes/bundle/commands/auth-login.js +84 -18
- package/hermes/bundle/pre-tool-use.js +40 -10
- package/hermes/bundle/session-end.js +305 -7
- package/hermes/bundle/session-start.js +68 -14
- package/hermes/bundle/shell/deeplake-shell.js +41 -11
- package/hermes/bundle/skilify-worker.js +907 -0
- package/mcp/bundle/server.js +41 -11
- package/openclaw/dist/chunks/{config-G23NI5TV.js → config-ZLH6JFJS.js} +1 -0
- package/openclaw/dist/index.js +185 -16
- package/openclaw/dist/skilify-worker.js +907 -0
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +2 -2
- package/openclaw/skills/SKILL.md +19 -0
- package/package.json +6 -1
- package/pi/extension-source/hivemind.ts +130 -1
package/codex/bundle/stop.js
CHANGED
|
@@ -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
|
|
57
|
-
import { fileURLToPath as
|
|
58
|
-
import { dirname as
|
|
56
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "node:fs";
|
|
57
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
58
|
+
import { dirname as dirname3, join as join13 } from "node:path";
|
|
59
59
|
|
|
60
60
|
// dist/src/utils/stdin.js
|
|
61
61
|
function readStdin() {
|
|
@@ -102,6 +102,7 @@ function loadConfig() {
|
|
|
102
102
|
apiUrl: process.env.HIVEMIND_API_URL ?? creds?.apiUrl ?? "https://api.deeplake.ai",
|
|
103
103
|
tableName: process.env.HIVEMIND_TABLE ?? "memory",
|
|
104
104
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
105
|
+
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
105
106
|
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
|
|
106
107
|
};
|
|
107
108
|
}
|
|
@@ -129,6 +130,12 @@ function log(tag, msg) {
|
|
|
129
130
|
function sqlStr(value) {
|
|
130
131
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
131
132
|
}
|
|
133
|
+
function sqlIdent(name) {
|
|
134
|
+
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
135
|
+
throw new Error(`Invalid SQL identifier: ${JSON.stringify(name)}`);
|
|
136
|
+
}
|
|
137
|
+
return name;
|
|
138
|
+
}
|
|
132
139
|
|
|
133
140
|
// dist/src/embeddings/columns.js
|
|
134
141
|
var SUMMARY_EMBEDDING_COL = "summary_embedding";
|
|
@@ -501,7 +508,7 @@ var DeeplakeApi = class {
|
|
|
501
508
|
}
|
|
502
509
|
/** Create the memory table if it doesn't already exist. Migrate columns on existing tables. */
|
|
503
510
|
async ensureTable(name) {
|
|
504
|
-
const tbl = name ?? this.tableName;
|
|
511
|
+
const tbl = sqlIdent(name ?? this.tableName);
|
|
505
512
|
const tables = await this.listTables();
|
|
506
513
|
if (!tables.includes(tbl)) {
|
|
507
514
|
log2(`table "${tbl}" not found, creating`);
|
|
@@ -515,17 +522,40 @@ var DeeplakeApi = class {
|
|
|
515
522
|
}
|
|
516
523
|
/** Create the sessions table (uses JSONB for message since every row is a JSON event). */
|
|
517
524
|
async ensureSessionsTable(name) {
|
|
525
|
+
const safe = sqlIdent(name);
|
|
526
|
+
const tables = await this.listTables();
|
|
527
|
+
if (!tables.includes(safe)) {
|
|
528
|
+
log2(`table "${safe}" not found, creating`);
|
|
529
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', path TEXT NOT NULL DEFAULT '', filename TEXT NOT NULL DEFAULT '', message JSONB, message_embedding FLOAT4[], author TEXT NOT NULL DEFAULT '', mime_type TEXT NOT NULL DEFAULT 'application/json', size_bytes BIGINT NOT NULL DEFAULT 0, project TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', agent TEXT NOT NULL DEFAULT '', creation_date TEXT NOT NULL DEFAULT '', last_update_date TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
530
|
+
log2(`table "${safe}" created`);
|
|
531
|
+
if (!tables.includes(safe))
|
|
532
|
+
this._tablesCache = [...tables, safe];
|
|
533
|
+
}
|
|
534
|
+
await this.ensureEmbeddingColumn(safe, MESSAGE_EMBEDDING_COL);
|
|
535
|
+
await this.ensureColumn(safe, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
536
|
+
await this.ensureLookupIndex(safe, "path_creation_date", `("path", "creation_date")`);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Create the skills table.
|
|
540
|
+
*
|
|
541
|
+
* One row per skill version. Workers INSERT a fresh row on every KEEP /
|
|
542
|
+
* MERGE rather than UPDATE-ing in place, so the full version history is
|
|
543
|
+
* recoverable. Uniqueness in the *current* state is by (project_key, name)
|
|
544
|
+
* — newer rows shadow older ones at read time (ORDER BY version DESC).
|
|
545
|
+
* This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
|
|
546
|
+
* worker.
|
|
547
|
+
*/
|
|
548
|
+
async ensureSkillsTable(name) {
|
|
549
|
+
const safe = sqlIdent(name);
|
|
518
550
|
const tables = await this.listTables();
|
|
519
|
-
if (!tables.includes(
|
|
520
|
-
log2(`table "${
|
|
521
|
-
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${
|
|
522
|
-
log2(`table "${
|
|
523
|
-
if (!tables.includes(
|
|
524
|
-
this._tablesCache = [...tables,
|
|
551
|
+
if (!tables.includes(safe)) {
|
|
552
|
+
log2(`table "${safe}" not found, creating`);
|
|
553
|
+
await this.createTableWithRetry(`CREATE TABLE IF NOT EXISTS "${safe}" (id TEXT NOT NULL DEFAULT '', name TEXT NOT NULL DEFAULT '', project TEXT NOT NULL DEFAULT '', project_key TEXT NOT NULL DEFAULT '', local_path TEXT NOT NULL DEFAULT '', install TEXT NOT NULL DEFAULT 'project', source_sessions TEXT NOT NULL DEFAULT '[]', source_agent TEXT NOT NULL DEFAULT '', scope TEXT NOT NULL DEFAULT 'me', author TEXT NOT NULL DEFAULT '', description TEXT NOT NULL DEFAULT '', trigger_text TEXT NOT NULL DEFAULT '', body TEXT NOT NULL DEFAULT '', version BIGINT NOT NULL DEFAULT 1, created_at TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT '') USING deeplake`, safe);
|
|
554
|
+
log2(`table "${safe}" created`);
|
|
555
|
+
if (!tables.includes(safe))
|
|
556
|
+
this._tablesCache = [...tables, safe];
|
|
525
557
|
}
|
|
526
|
-
await this.
|
|
527
|
-
await this.ensureColumn(name, "agent", "TEXT NOT NULL DEFAULT ''");
|
|
528
|
-
await this.ensureLookupIndex(name, "path_creation_date", `("path", "creation_date")`);
|
|
558
|
+
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
529
559
|
}
|
|
530
560
|
};
|
|
531
561
|
|
|
@@ -649,31 +679,207 @@ function bundleDirFromImportMeta(importMetaUrl) {
|
|
|
649
679
|
return dirname(fileURLToPath(importMetaUrl));
|
|
650
680
|
}
|
|
651
681
|
|
|
652
|
-
// dist/src/
|
|
653
|
-
import {
|
|
682
|
+
// dist/src/skilify/spawn-skilify-worker.js
|
|
683
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
684
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
685
|
+
import { dirname as dirname2, join as join7 } from "node:path";
|
|
686
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, appendFileSync as appendFileSync3, chmodSync } from "node:fs";
|
|
687
|
+
import { homedir as homedir5, tmpdir as tmpdir3 } from "node:os";
|
|
688
|
+
|
|
689
|
+
// dist/src/skilify/gate-runner.js
|
|
690
|
+
import { execFileSync } from "node:child_process";
|
|
691
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
654
692
|
import { homedir as homedir4 } from "node:os";
|
|
655
693
|
import { join as join6 } from "node:path";
|
|
656
|
-
|
|
657
|
-
|
|
694
|
+
function findAgentBin(agent) {
|
|
695
|
+
const which = (name) => {
|
|
696
|
+
try {
|
|
697
|
+
const out = execFileSync("which", [name], {
|
|
698
|
+
encoding: "utf-8",
|
|
699
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
700
|
+
});
|
|
701
|
+
return out.trim() || null;
|
|
702
|
+
} catch {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
switch (agent) {
|
|
707
|
+
case "claude_code":
|
|
708
|
+
return which("claude") ?? join6(homedir4(), ".claude", "local", "claude");
|
|
709
|
+
case "codex":
|
|
710
|
+
return which("codex") ?? "/usr/local/bin/codex";
|
|
711
|
+
case "cursor":
|
|
712
|
+
return which("cursor-agent") ?? "/usr/local/bin/cursor-agent";
|
|
713
|
+
case "hermes":
|
|
714
|
+
return which("hermes") ?? join6(homedir4(), ".local", "bin", "hermes");
|
|
715
|
+
case "pi":
|
|
716
|
+
return which("pi") ?? join6(homedir4(), ".local", "bin", "pi");
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// dist/src/skilify/spawn-skilify-worker.js
|
|
721
|
+
var HOME2 = homedir5();
|
|
722
|
+
var SKILIFY_LOG = join7(HOME2, ".claude", "hooks", "skilify.log");
|
|
723
|
+
function skilifyLog(msg) {
|
|
724
|
+
try {
|
|
725
|
+
mkdirSync4(dirname2(SKILIFY_LOG), { recursive: true });
|
|
726
|
+
appendFileSync3(SKILIFY_LOG, `[${utcTimestamp()}] ${msg}
|
|
727
|
+
`);
|
|
728
|
+
} catch {
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
function spawnSkilifyWorker(opts) {
|
|
732
|
+
const { config, cwd, projectKey, project, bundleDir, agent, scopeConfig, currentSessionId, reason } = opts;
|
|
733
|
+
const tmpDir = join7(tmpdir3(), `deeplake-skilify-${projectKey}-${Date.now()}`);
|
|
734
|
+
mkdirSync4(tmpDir, { recursive: true, mode: 448 });
|
|
735
|
+
const gateBin = findAgentBin(agent);
|
|
736
|
+
const configFile = join7(tmpDir, "config.json");
|
|
737
|
+
writeFileSync3(configFile, JSON.stringify({
|
|
738
|
+
apiUrl: config.apiUrl,
|
|
739
|
+
token: config.token,
|
|
740
|
+
orgId: config.orgId,
|
|
741
|
+
workspaceId: config.workspaceId,
|
|
742
|
+
sessionsTable: config.sessionsTableName,
|
|
743
|
+
skillsTable: config.skillsTableName,
|
|
744
|
+
userName: config.userName,
|
|
745
|
+
cwd,
|
|
746
|
+
projectKey,
|
|
747
|
+
project,
|
|
748
|
+
agent,
|
|
749
|
+
scope: scopeConfig.scope,
|
|
750
|
+
team: scopeConfig.team,
|
|
751
|
+
install: scopeConfig.install,
|
|
752
|
+
tmpDir,
|
|
753
|
+
gateBin,
|
|
754
|
+
cursorModel: process.env.HIVEMIND_CURSOR_MODEL,
|
|
755
|
+
hermesProvider: process.env.HIVEMIND_HERMES_PROVIDER,
|
|
756
|
+
hermesModel: process.env.HIVEMIND_HERMES_MODEL,
|
|
757
|
+
piProvider: process.env.HIVEMIND_PI_PROVIDER,
|
|
758
|
+
piModel: process.env.HIVEMIND_PI_MODEL,
|
|
759
|
+
skilifyLog: SKILIFY_LOG,
|
|
760
|
+
currentSessionId
|
|
761
|
+
}), { mode: 384 });
|
|
762
|
+
try {
|
|
763
|
+
chmodSync(configFile, 384);
|
|
764
|
+
} catch {
|
|
765
|
+
}
|
|
766
|
+
skilifyLog(`${reason}: spawning skilify worker for project=${project} key=${projectKey}`);
|
|
767
|
+
const workerPath = join7(bundleDir, "skilify-worker.js");
|
|
768
|
+
spawn2("nohup", ["node", workerPath, configFile], {
|
|
769
|
+
detached: true,
|
|
770
|
+
stdio: ["ignore", "ignore", "ignore"]
|
|
771
|
+
}).unref();
|
|
772
|
+
skilifyLog(`${reason}: spawned skilify worker for ${projectKey}`);
|
|
773
|
+
}
|
|
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";
|
|
777
|
+
import { execSync as execSync2 } from "node:child_process";
|
|
778
|
+
import { homedir as homedir6 } from "node:os";
|
|
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");
|
|
658
783
|
var YIELD_BUF = new Int32Array(new SharedArrayBuffer(4));
|
|
659
|
-
|
|
660
|
-
|
|
784
|
+
var TRIGGER_THRESHOLD = (() => {
|
|
785
|
+
const n = Number(process.env.HIVEMIND_SKILIFY_EVERY_N_TURNS ?? "");
|
|
786
|
+
return Number.isInteger(n) && n > 0 ? n : 20;
|
|
787
|
+
})();
|
|
788
|
+
function statePath(projectKey) {
|
|
789
|
+
return join8(STATE_DIR, `${projectKey}.json`);
|
|
661
790
|
}
|
|
662
|
-
function
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
791
|
+
function lockPath(projectKey) {
|
|
792
|
+
return join8(STATE_DIR, `${projectKey}.lock`);
|
|
793
|
+
}
|
|
794
|
+
function deriveProjectKey(cwd) {
|
|
795
|
+
const project = basename(cwd) || "unknown";
|
|
796
|
+
let signature = null;
|
|
797
|
+
try {
|
|
798
|
+
signature = execSync2("git config --get remote.origin.url", {
|
|
799
|
+
cwd,
|
|
800
|
+
encoding: "utf-8",
|
|
801
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
802
|
+
}).trim() || null;
|
|
803
|
+
} catch {
|
|
804
|
+
}
|
|
805
|
+
const input = signature ?? cwd;
|
|
806
|
+
const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
|
|
807
|
+
return { key, project };
|
|
808
|
+
}
|
|
809
|
+
function readState(projectKey) {
|
|
810
|
+
const p = statePath(projectKey);
|
|
811
|
+
if (!existsSync4(p))
|
|
812
|
+
return null;
|
|
813
|
+
try {
|
|
814
|
+
return JSON.parse(readFileSync3(p, "utf-8"));
|
|
815
|
+
} catch {
|
|
816
|
+
return null;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
function writeState(projectKey, state) {
|
|
820
|
+
mkdirSync5(STATE_DIR, { recursive: true });
|
|
821
|
+
const p = statePath(projectKey);
|
|
822
|
+
const tmp = `${p}.${process.pid}.${Date.now()}.tmp`;
|
|
823
|
+
writeFileSync4(tmp, JSON.stringify(state, null, 2));
|
|
824
|
+
renameSync(tmp, p);
|
|
825
|
+
}
|
|
826
|
+
function withRmwLock(projectKey, fn) {
|
|
827
|
+
mkdirSync5(STATE_DIR, { recursive: true });
|
|
828
|
+
const rmw = lockPath(projectKey) + ".rmw";
|
|
829
|
+
const deadline = Date.now() + 2e3;
|
|
830
|
+
let fd = null;
|
|
831
|
+
while (fd === null) {
|
|
832
|
+
try {
|
|
833
|
+
fd = openSync(rmw, "wx");
|
|
834
|
+
} catch (e) {
|
|
835
|
+
if (e.code !== "EEXIST")
|
|
836
|
+
throw e;
|
|
837
|
+
if (Date.now() > deadline) {
|
|
838
|
+
dlog(`rmw lock deadline exceeded for ${projectKey}, reclaiming stale lock`);
|
|
839
|
+
try {
|
|
840
|
+
unlinkSync(rmw);
|
|
841
|
+
} catch (unlinkErr) {
|
|
842
|
+
dlog(`stale rmw lock unlink failed for ${projectKey}: ${unlinkErr.message}`);
|
|
843
|
+
}
|
|
844
|
+
continue;
|
|
845
|
+
}
|
|
846
|
+
Atomics.wait(YIELD_BUF, 0, 0, 10);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
try {
|
|
850
|
+
return fn();
|
|
851
|
+
} finally {
|
|
852
|
+
closeSync(fd);
|
|
853
|
+
try {
|
|
854
|
+
unlinkSync(rmw);
|
|
855
|
+
} catch (unlinkErr) {
|
|
856
|
+
dlog(`rmw lock cleanup failed for ${projectKey}: ${unlinkErr.message}`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
function resetCounter(projectKey) {
|
|
861
|
+
withRmwLock(projectKey, () => {
|
|
862
|
+
const s = readState(projectKey);
|
|
863
|
+
if (!s)
|
|
864
|
+
return;
|
|
865
|
+
writeState(projectKey, { ...s, counter: 0, updatedAt: Date.now() });
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
function tryAcquireWorkerLock(projectKey, maxAgeMs = 10 * 60 * 1e3) {
|
|
869
|
+
mkdirSync5(STATE_DIR, { recursive: true });
|
|
870
|
+
const p = lockPath(projectKey);
|
|
871
|
+
if (existsSync4(p)) {
|
|
666
872
|
try {
|
|
667
873
|
const ageMs = Date.now() - parseInt(readFileSync3(p, "utf-8"), 10);
|
|
668
874
|
if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
|
|
669
875
|
return false;
|
|
670
876
|
} catch (readErr) {
|
|
671
|
-
dlog(`lock
|
|
877
|
+
dlog(`worker lock unreadable for ${projectKey}, treating as stale: ${readErr.message}`);
|
|
672
878
|
}
|
|
673
879
|
try {
|
|
674
880
|
unlinkSync(p);
|
|
675
881
|
} catch (unlinkErr) {
|
|
676
|
-
dlog(`could not unlink stale lock for ${
|
|
882
|
+
dlog(`could not unlink stale worker lock for ${projectKey}: ${unlinkErr.message}`);
|
|
677
883
|
return false;
|
|
678
884
|
}
|
|
679
885
|
}
|
|
@@ -685,6 +891,115 @@ function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
685
891
|
closeSync(fd);
|
|
686
892
|
}
|
|
687
893
|
return true;
|
|
894
|
+
} catch {
|
|
895
|
+
return false;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
function releaseWorkerLock(projectKey) {
|
|
899
|
+
const p = lockPath(projectKey);
|
|
900
|
+
try {
|
|
901
|
+
unlinkSync(p);
|
|
902
|
+
} catch {
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
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");
|
|
912
|
+
var DEFAULT = { scope: "me", team: [], install: "project" };
|
|
913
|
+
function loadScopeConfig() {
|
|
914
|
+
if (!existsSync5(CONFIG_PATH))
|
|
915
|
+
return DEFAULT;
|
|
916
|
+
try {
|
|
917
|
+
const raw = JSON.parse(readFileSync4(CONFIG_PATH, "utf-8"));
|
|
918
|
+
const scope = raw.scope === "team" || raw.scope === "org" ? raw.scope : "me";
|
|
919
|
+
const team = Array.isArray(raw.team) ? raw.team.filter((s) => typeof s === "string") : [];
|
|
920
|
+
const install = raw.install === "global" ? "global" : "project";
|
|
921
|
+
return { scope, team, install };
|
|
922
|
+
} catch {
|
|
923
|
+
return DEFAULT;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// dist/src/skilify/triggers.js
|
|
928
|
+
function forceSessionEndTrigger(opts) {
|
|
929
|
+
if (process.env.HIVEMIND_SKILIFY_WORKER === "1")
|
|
930
|
+
return;
|
|
931
|
+
if (!opts.cwd)
|
|
932
|
+
return;
|
|
933
|
+
try {
|
|
934
|
+
const { key: projectKey, project } = deriveProjectKey(opts.cwd);
|
|
935
|
+
if (!tryAcquireWorkerLock(projectKey)) {
|
|
936
|
+
skilifyLog(`SessionEnd: skilify worker already running for ${projectKey}, skipping`);
|
|
937
|
+
return;
|
|
938
|
+
}
|
|
939
|
+
if (readState(projectKey)) {
|
|
940
|
+
resetCounter(projectKey);
|
|
941
|
+
}
|
|
942
|
+
skilifyLog(`SessionEnd: spawning skilify worker for project=${project} agent=${opts.agent}`);
|
|
943
|
+
try {
|
|
944
|
+
spawnSkilifyWorker({
|
|
945
|
+
config: opts.config,
|
|
946
|
+
cwd: opts.cwd,
|
|
947
|
+
projectKey,
|
|
948
|
+
project,
|
|
949
|
+
bundleDir: opts.bundleDir,
|
|
950
|
+
agent: opts.agent,
|
|
951
|
+
scopeConfig: loadScopeConfig(),
|
|
952
|
+
currentSessionId: opts.sessionId,
|
|
953
|
+
reason: "SessionEnd"
|
|
954
|
+
});
|
|
955
|
+
} catch (e) {
|
|
956
|
+
skilifyLog(`SessionEnd spawn failed: ${e?.message ?? e}`);
|
|
957
|
+
try {
|
|
958
|
+
releaseWorkerLock(projectKey);
|
|
959
|
+
} catch {
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
} catch (e) {
|
|
963
|
+
skilifyLog(`SessionEnd trigger error: ${e?.message ?? e}`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// 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");
|
|
973
|
+
var YIELD_BUF2 = new Int32Array(new SharedArrayBuffer(4));
|
|
974
|
+
function lockPath2(sessionId) {
|
|
975
|
+
return join10(STATE_DIR3, `${sessionId}.lock`);
|
|
976
|
+
}
|
|
977
|
+
function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
978
|
+
mkdirSync7(STATE_DIR3, { recursive: true });
|
|
979
|
+
const p = lockPath2(sessionId);
|
|
980
|
+
if (existsSync6(p)) {
|
|
981
|
+
try {
|
|
982
|
+
const ageMs = Date.now() - parseInt(readFileSync5(p, "utf-8"), 10);
|
|
983
|
+
if (Number.isFinite(ageMs) && ageMs < maxAgeMs)
|
|
984
|
+
return false;
|
|
985
|
+
} catch (readErr) {
|
|
986
|
+
dlog2(`lock file unreadable for ${sessionId}, treating as stale: ${readErr.message}`);
|
|
987
|
+
}
|
|
988
|
+
try {
|
|
989
|
+
unlinkSync2(p);
|
|
990
|
+
} catch (unlinkErr) {
|
|
991
|
+
dlog2(`could not unlink stale lock for ${sessionId}: ${unlinkErr.message}`);
|
|
992
|
+
return false;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
try {
|
|
996
|
+
const fd = openSync2(p, "wx");
|
|
997
|
+
try {
|
|
998
|
+
writeSync2(fd, String(Date.now()));
|
|
999
|
+
} finally {
|
|
1000
|
+
closeSync2(fd);
|
|
1001
|
+
}
|
|
1002
|
+
return true;
|
|
688
1003
|
} catch (e) {
|
|
689
1004
|
if (e.code === "EEXIST")
|
|
690
1005
|
return false;
|
|
@@ -693,10 +1008,10 @@ function tryAcquireLock(sessionId, maxAgeMs = 10 * 60 * 1e3) {
|
|
|
693
1008
|
}
|
|
694
1009
|
function releaseLock(sessionId) {
|
|
695
1010
|
try {
|
|
696
|
-
|
|
1011
|
+
unlinkSync2(lockPath2(sessionId));
|
|
697
1012
|
} catch (e) {
|
|
698
1013
|
if (e?.code !== "ENOENT") {
|
|
699
|
-
|
|
1014
|
+
dlog2(`releaseLock unlink failed for ${sessionId}: ${e.message}`);
|
|
700
1015
|
}
|
|
701
1016
|
}
|
|
702
1017
|
}
|
|
@@ -709,10 +1024,10 @@ function buildSessionPath(config, sessionId) {
|
|
|
709
1024
|
|
|
710
1025
|
// dist/src/embeddings/client.js
|
|
711
1026
|
import { connect } from "node:net";
|
|
712
|
-
import { spawn as
|
|
713
|
-
import { openSync as
|
|
714
|
-
import { homedir as
|
|
715
|
-
import { join as
|
|
1027
|
+
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";
|
|
716
1031
|
|
|
717
1032
|
// dist/src/embeddings/protocol.js
|
|
718
1033
|
var DEFAULT_SOCKET_DIR = "/tmp";
|
|
@@ -726,7 +1041,7 @@ function pidPathFor(uid, dir = DEFAULT_SOCKET_DIR) {
|
|
|
726
1041
|
}
|
|
727
1042
|
|
|
728
1043
|
// dist/src/embeddings/client.js
|
|
729
|
-
var SHARED_DAEMON_PATH =
|
|
1044
|
+
var SHARED_DAEMON_PATH = join11(homedir9(), ".hivemind", "embed-deps", "embed-daemon.js");
|
|
730
1045
|
var log3 = (m) => log("embed-client", m);
|
|
731
1046
|
function getUid() {
|
|
732
1047
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
@@ -746,7 +1061,7 @@ var EmbedClient = class {
|
|
|
746
1061
|
this.socketPath = socketPathFor(uid, dir);
|
|
747
1062
|
this.pidPath = pidPathFor(uid, dir);
|
|
748
1063
|
this.timeoutMs = opts.timeoutMs ?? DEFAULT_CLIENT_TIMEOUT_MS;
|
|
749
|
-
this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (
|
|
1064
|
+
this.daemonEntry = opts.daemonEntry ?? process.env.HIVEMIND_EMBED_DAEMON ?? (existsSync7(SHARED_DAEMON_PATH) ? SHARED_DAEMON_PATH : void 0);
|
|
750
1065
|
this.autoSpawn = opts.autoSpawn ?? true;
|
|
751
1066
|
this.spawnWaitMs = opts.spawnWaitMs ?? 5e3;
|
|
752
1067
|
}
|
|
@@ -828,17 +1143,17 @@ var EmbedClient = class {
|
|
|
828
1143
|
trySpawnDaemon() {
|
|
829
1144
|
let fd;
|
|
830
1145
|
try {
|
|
831
|
-
fd =
|
|
832
|
-
|
|
1146
|
+
fd = openSync3(this.pidPath, "wx", 384);
|
|
1147
|
+
writeSync3(fd, String(process.pid));
|
|
833
1148
|
} catch (e) {
|
|
834
1149
|
if (this.isPidFileStale()) {
|
|
835
1150
|
try {
|
|
836
|
-
|
|
1151
|
+
unlinkSync3(this.pidPath);
|
|
837
1152
|
} catch {
|
|
838
1153
|
}
|
|
839
1154
|
try {
|
|
840
|
-
fd =
|
|
841
|
-
|
|
1155
|
+
fd = openSync3(this.pidPath, "wx", 384);
|
|
1156
|
+
writeSync3(fd, String(process.pid));
|
|
842
1157
|
} catch {
|
|
843
1158
|
return;
|
|
844
1159
|
}
|
|
@@ -846,17 +1161,17 @@ var EmbedClient = class {
|
|
|
846
1161
|
return;
|
|
847
1162
|
}
|
|
848
1163
|
}
|
|
849
|
-
if (!this.daemonEntry || !
|
|
1164
|
+
if (!this.daemonEntry || !existsSync7(this.daemonEntry)) {
|
|
850
1165
|
log3(`daemonEntry not configured or missing: ${this.daemonEntry}`);
|
|
851
1166
|
try {
|
|
852
|
-
|
|
853
|
-
|
|
1167
|
+
closeSync3(fd);
|
|
1168
|
+
unlinkSync3(this.pidPath);
|
|
854
1169
|
} catch {
|
|
855
1170
|
}
|
|
856
1171
|
return;
|
|
857
1172
|
}
|
|
858
1173
|
try {
|
|
859
|
-
const child =
|
|
1174
|
+
const child = spawn3(process.execPath, [this.daemonEntry], {
|
|
860
1175
|
detached: true,
|
|
861
1176
|
stdio: "ignore",
|
|
862
1177
|
env: process.env
|
|
@@ -864,12 +1179,12 @@ var EmbedClient = class {
|
|
|
864
1179
|
child.unref();
|
|
865
1180
|
log3(`spawned daemon pid=${child.pid}`);
|
|
866
1181
|
} finally {
|
|
867
|
-
|
|
1182
|
+
closeSync3(fd);
|
|
868
1183
|
}
|
|
869
1184
|
}
|
|
870
1185
|
isPidFileStale() {
|
|
871
1186
|
try {
|
|
872
|
-
const raw =
|
|
1187
|
+
const raw = readFileSync6(this.pidPath, "utf-8").trim();
|
|
873
1188
|
const pid = Number(raw);
|
|
874
1189
|
if (!pid || Number.isNaN(pid))
|
|
875
1190
|
return true;
|
|
@@ -889,7 +1204,7 @@ var EmbedClient = class {
|
|
|
889
1204
|
while (Date.now() < deadline) {
|
|
890
1205
|
await sleep2(delay);
|
|
891
1206
|
delay = Math.min(delay * 1.5, 300);
|
|
892
|
-
if (!
|
|
1207
|
+
if (!existsSync7(this.socketPath))
|
|
893
1208
|
continue;
|
|
894
1209
|
try {
|
|
895
1210
|
return await this.connectOnce();
|
|
@@ -950,8 +1265,8 @@ function embeddingSqlLiteral(vec) {
|
|
|
950
1265
|
|
|
951
1266
|
// dist/src/embeddings/disable.js
|
|
952
1267
|
import { createRequire } from "node:module";
|
|
953
|
-
import { homedir as
|
|
954
|
-
import { join as
|
|
1268
|
+
import { homedir as homedir10 } from "node:os";
|
|
1269
|
+
import { join as join12 } from "node:path";
|
|
955
1270
|
import { pathToFileURL } from "node:url";
|
|
956
1271
|
var cachedStatus = null;
|
|
957
1272
|
function defaultResolveTransformers() {
|
|
@@ -960,7 +1275,7 @@ function defaultResolveTransformers() {
|
|
|
960
1275
|
return;
|
|
961
1276
|
} catch {
|
|
962
1277
|
}
|
|
963
|
-
const sharedDir =
|
|
1278
|
+
const sharedDir = join12(homedir10(), ".hivemind", "embed-deps");
|
|
964
1279
|
createRequire(pathToFileURL(`${sharedDir}/`).href).resolve("@huggingface/transformers");
|
|
965
1280
|
}
|
|
966
1281
|
var _resolve = defaultResolveTransformers;
|
|
@@ -987,7 +1302,7 @@ function embeddingsDisabled() {
|
|
|
987
1302
|
// dist/src/hooks/codex/stop.js
|
|
988
1303
|
var log4 = (msg) => log("codex-stop", msg);
|
|
989
1304
|
function resolveEmbedDaemonPath() {
|
|
990
|
-
return
|
|
1305
|
+
return join13(dirname3(fileURLToPath3(import.meta.url)), "embeddings", "embed-daemon.js");
|
|
991
1306
|
}
|
|
992
1307
|
var CAPTURE = process.env.HIVEMIND_CAPTURE !== "false";
|
|
993
1308
|
async function main() {
|
|
@@ -1011,8 +1326,8 @@ async function main() {
|
|
|
1011
1326
|
if (input.transcript_path) {
|
|
1012
1327
|
try {
|
|
1013
1328
|
const transcriptPath = input.transcript_path;
|
|
1014
|
-
if (
|
|
1015
|
-
const transcript =
|
|
1329
|
+
if (existsSync8(transcriptPath)) {
|
|
1330
|
+
const transcript = readFileSync7(transcriptPath, "utf-8");
|
|
1016
1331
|
const lines = transcript.trim().split("\n").reverse();
|
|
1017
1332
|
for (const line2 of lines) {
|
|
1018
1333
|
try {
|
|
@@ -1084,6 +1399,13 @@ async function main() {
|
|
|
1084
1399
|
}
|
|
1085
1400
|
throw e;
|
|
1086
1401
|
}
|
|
1402
|
+
forceSessionEndTrigger({
|
|
1403
|
+
config,
|
|
1404
|
+
cwd: input.cwd ?? "",
|
|
1405
|
+
bundleDir: bundleDirFromImportMeta(import.meta.url),
|
|
1406
|
+
agent: "codex",
|
|
1407
|
+
sessionId
|
|
1408
|
+
});
|
|
1087
1409
|
}
|
|
1088
1410
|
main().catch((e) => {
|
|
1089
1411
|
log4(`fatal: ${e.message}`);
|