@mnemonik/cli 7.127.2 → 7.127.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/credentials.js +25 -0
- package/dist/auth/index.js +25 -0
- package/dist/diagnostics.js +25 -0
- package/dist/digests.json +28 -28
- package/dist/identity/migrate.js +25 -0
- package/dist/install/journal.js +25 -0
- package/dist/install/journey.js +25 -0
- package/dist/install/ownership.js +25 -0
- package/dist/install/transaction.js +25 -0
- package/dist/install/ui.js +25 -0
- package/dist/installation.js +25 -0
- package/dist/launcher.js +25 -0
- package/dist/project/eligibility.js +25 -0
- package/dist/project/records.js +25 -0
- package/dist/project.js +25 -0
- package/dist/router.js +25 -0
- package/dist/runtime/releaseSource.js +25 -0
- package/dist/runtime/selfUpdate.js +25 -0
- package/dist/runtime/signers.js +377 -49
- package/dist/runtime/store.js +19 -0
- package/dist/runtime/updateCheck.js +25 -0
- package/dist/sbom.json +21 -21
- package/dist/scanner/control.js +25 -0
- package/dist/scanner/enable.js +25 -0
- package/dist/scanner/service.js +25 -0
- package/dist/scanner/update.js +25 -0
- package/dist/scanner-release.json +24 -24
- package/dist/status.js +25 -0
- package/dist/vendor/local-setup.js +25 -0
- package/package.json +31 -31
package/dist/runtime/signers.js
CHANGED
|
@@ -187,8 +187,8 @@ function privateEntries(entries, user, directory) {
|
|
|
187
187
|
function* prepareAclDirectory(state) {
|
|
188
188
|
const directory = join(state, "audit-tmp");
|
|
189
189
|
if (auditDirectories.has(directory)) {
|
|
190
|
-
const
|
|
191
|
-
if (!
|
|
190
|
+
const stat3 = lstatSync(directory);
|
|
191
|
+
if (!stat3.isDirectory() || stat3.isSymbolicLink())
|
|
192
192
|
throw new Error("acl_permissions");
|
|
193
193
|
return directory;
|
|
194
194
|
}
|
|
@@ -200,8 +200,8 @@ function* prepareAclDirectory(state) {
|
|
|
200
200
|
if (error.code !== "EEXIST")
|
|
201
201
|
throw error;
|
|
202
202
|
}
|
|
203
|
-
const
|
|
204
|
-
if (!
|
|
203
|
+
const stat2 = lstatSync(directory);
|
|
204
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
205
205
|
throw new Error("acl_permissions");
|
|
206
206
|
if (!auditDirectories.has(directory)) {
|
|
207
207
|
currentIdentity ??= yield* readWindowsIdentity();
|
|
@@ -291,8 +291,8 @@ function ownerSids(output) {
|
|
|
291
291
|
return owners;
|
|
292
292
|
}
|
|
293
293
|
function* hookPermission(path, created, session, directory = true) {
|
|
294
|
-
const
|
|
295
|
-
if (
|
|
294
|
+
const stat2 = lstatSync(path);
|
|
295
|
+
if (stat2.isSymbolicLink() || (directory ? !stat2.isDirectory() : !stat2.isFile()))
|
|
296
296
|
throw new Error("cache unavailable");
|
|
297
297
|
const marker = join(session, ".windows-acl.json");
|
|
298
298
|
let receipt = receipts.get(session);
|
|
@@ -469,8 +469,8 @@ var init_runtimeSigners = __esm({
|
|
|
469
469
|
const result = promisify(execFile)(file, args);
|
|
470
470
|
if (input === void 0)
|
|
471
471
|
return result;
|
|
472
|
-
return new Promise((
|
|
473
|
-
void result.then(
|
|
472
|
+
return new Promise((resolve5, reject2) => {
|
|
473
|
+
void result.then(resolve5, reject2);
|
|
474
474
|
result.child.stdin?.on("error", reject2);
|
|
475
475
|
result.child.stdin?.end(input);
|
|
476
476
|
});
|
|
@@ -503,8 +503,8 @@ var init_runtimeSigners = __esm({
|
|
|
503
503
|
const options = hookOptions(file, args);
|
|
504
504
|
if (treeListing)
|
|
505
505
|
options.timeout = 3e4;
|
|
506
|
-
return new Promise((
|
|
507
|
-
const child = execFile(file, args, options, (error, stdout2) => error ? reject2(error) :
|
|
506
|
+
return new Promise((resolve5, reject2) => {
|
|
507
|
+
const child = execFile(file, args, options, (error, stdout2) => error ? reject2(error) : resolve5({ stdout: stdout2 }));
|
|
508
508
|
if (input !== void 0) {
|
|
509
509
|
child.stdin?.on("error", reject2);
|
|
510
510
|
child.stdin?.end(input);
|
|
@@ -596,10 +596,10 @@ function parseIdentityFile(text) {
|
|
|
596
596
|
async function readIdentityFile(dir, options = {}) {
|
|
597
597
|
const path = join2(dir, ".mnemonik.json");
|
|
598
598
|
try {
|
|
599
|
-
const
|
|
600
|
-
if (
|
|
599
|
+
const stat2 = await lstat(path);
|
|
600
|
+
if (stat2.isSymbolicLink())
|
|
601
601
|
return { kind: "malformed", detail: "symlink" };
|
|
602
|
-
if (!
|
|
602
|
+
if (!stat2.isFile())
|
|
603
603
|
return { kind: "malformed", detail: "identity path is not a regular file" };
|
|
604
604
|
const text = await readFile2(path, "utf8");
|
|
605
605
|
if (options.selectedRoot) {
|
|
@@ -659,10 +659,10 @@ function runGit(cwd, args) {
|
|
|
659
659
|
}
|
|
660
660
|
async function boundaryAt(path) {
|
|
661
661
|
try {
|
|
662
|
-
const
|
|
663
|
-
if (
|
|
662
|
+
const stat2 = await lstat2(join3(path, ".git"));
|
|
663
|
+
if (stat2.isDirectory())
|
|
664
664
|
return { path, kind: "directory" };
|
|
665
|
-
if (
|
|
665
|
+
if (stat2.isFile())
|
|
666
666
|
return { path, kind: "file" };
|
|
667
667
|
} catch (error) {
|
|
668
668
|
const code = error.code;
|
|
@@ -879,7 +879,7 @@ var init_runtimeReader = __esm({
|
|
|
879
879
|
throw new RuntimeError("permission");
|
|
880
880
|
return v;
|
|
881
881
|
};
|
|
882
|
-
statIdentity = (
|
|
882
|
+
statIdentity = (stat2) => [stat2.dev, stat2.ino, stat2.mode, stat2.uid, stat2.size, stat2.mtimeMs, stat2.ctimeMs].join(":");
|
|
883
883
|
RuntimeReader = class _RuntimeReader {
|
|
884
884
|
run;
|
|
885
885
|
options;
|
|
@@ -1003,14 +1003,14 @@ var init_runtimeReader = __esm({
|
|
|
1003
1003
|
let part = parse(absolute).root;
|
|
1004
1004
|
for (const name of absolute.slice(part.length).split(sep2)) {
|
|
1005
1005
|
part = join4(part, name);
|
|
1006
|
-
const
|
|
1006
|
+
const stat2 = await lstat3(part).catch((e) => {
|
|
1007
1007
|
if (allowMissing && missing(e))
|
|
1008
1008
|
return null;
|
|
1009
1009
|
throw e;
|
|
1010
1010
|
});
|
|
1011
|
-
if (!
|
|
1011
|
+
if (!stat2)
|
|
1012
1012
|
break;
|
|
1013
|
-
if (
|
|
1013
|
+
if (stat2.isSymbolicLink() || (part === absolute ? directory ? !stat2.isDirectory() : !stat2.isFile() : !stat2.isDirectory()))
|
|
1014
1014
|
throw new RuntimeError("permission");
|
|
1015
1015
|
if (part !== this.state && !part.startsWith(this.state + sep2))
|
|
1016
1016
|
continue;
|
|
@@ -1021,11 +1021,11 @@ var init_runtimeReader = __esm({
|
|
|
1021
1021
|
await prepareWindowsAclDirectory(this.state, this.run).catch((error) => {
|
|
1022
1022
|
throw new RuntimeError(error instanceof Error && error.message === "acl_permissions" ? "permission" : "acl_unavailable");
|
|
1023
1023
|
});
|
|
1024
|
-
Object.assign(
|
|
1024
|
+
Object.assign(stat2, await lstat3(part));
|
|
1025
1025
|
}
|
|
1026
|
-
if (
|
|
1026
|
+
if (stat2.isDirectory())
|
|
1027
1027
|
this.windowsDirectories.add(part);
|
|
1028
|
-
const identity = statIdentity(
|
|
1028
|
+
const identity = statIdentity(stat2);
|
|
1029
1029
|
const previous = this.windowsStats.get(part);
|
|
1030
1030
|
if (previous !== void 0 && previous !== identity) {
|
|
1031
1031
|
this.traceAudit({
|
|
@@ -1041,7 +1041,7 @@ var init_runtimeReader = __esm({
|
|
|
1041
1041
|
}
|
|
1042
1042
|
this.windowsStats.set(part, identity);
|
|
1043
1043
|
windowsPaths.push(part);
|
|
1044
|
-
} else if (
|
|
1044
|
+
} else if (stat2.uid !== process.getuid?.() || (stat2.mode & 63) !== 0)
|
|
1045
1045
|
throw new RuntimeError("permission");
|
|
1046
1046
|
}
|
|
1047
1047
|
await this.audit(windowsPaths);
|
|
@@ -1057,10 +1057,10 @@ var init_runtimeReader = __esm({
|
|
|
1057
1057
|
return;
|
|
1058
1058
|
const absolute = this.guardedPath(path);
|
|
1059
1059
|
const parent = dirname3(absolute);
|
|
1060
|
-
const
|
|
1061
|
-
if (!
|
|
1060
|
+
const stat2 = await lstat3(parent);
|
|
1061
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink() || !this.windowsStats.get(parent)?.startsWith(`${stat2.dev}:${stat2.ino}:`))
|
|
1062
1062
|
throw new RuntimeError("permission");
|
|
1063
|
-
this.windowsStats.set(parent, statIdentity(
|
|
1063
|
+
this.windowsStats.set(parent, statIdentity(stat2));
|
|
1064
1064
|
this.windowsAudit.delete(absolute);
|
|
1065
1065
|
this.windowsStats.delete(absolute);
|
|
1066
1066
|
}
|
|
@@ -1307,7 +1307,7 @@ async function waitForResult(path, waitMs) {
|
|
|
1307
1307
|
return result;
|
|
1308
1308
|
if (Date.now() >= deadline)
|
|
1309
1309
|
return RUNNING;
|
|
1310
|
-
await new Promise((
|
|
1310
|
+
await new Promise((resolve5) => setTimeout(resolve5, Math.min(50, deadline - Date.now())));
|
|
1311
1311
|
}
|
|
1312
1312
|
}
|
|
1313
1313
|
async function runEnsure(options) {
|
|
@@ -1469,8 +1469,8 @@ async function pendingProjectSetup(root) {
|
|
|
1469
1469
|
for (const host of ["credit", "cursor", "grok"]) {
|
|
1470
1470
|
const directory = join5(tmpdir(), `mnemonik-${host}-${uid}`);
|
|
1471
1471
|
try {
|
|
1472
|
-
const
|
|
1473
|
-
if (
|
|
1472
|
+
const stat2 = await lstat4(directory);
|
|
1473
|
+
if (stat2.isSymbolicLink() || !stat2.isDirectory())
|
|
1474
1474
|
continue;
|
|
1475
1475
|
for (const name of await readdir2(directory)) {
|
|
1476
1476
|
if (!/^[a-f0-9]{64}$/.test(name))
|
|
@@ -1529,6 +1529,319 @@ process.stdin.on('end', () => {
|
|
|
1529
1529
|
}
|
|
1530
1530
|
});
|
|
1531
1531
|
|
|
1532
|
+
// packages/shared/dist/settingsIo.js
|
|
1533
|
+
import { createHash as createHash3, randomBytes } from "node:crypto";
|
|
1534
|
+
import { link, lstat as lstat5, mkdir as mkdir2, open as open3, readFile as readFile4, readdir as readdir3, realpath as realpath2, rename as rename2, rm as rm2, rmdir, stat, unlink } from "node:fs/promises";
|
|
1535
|
+
import { basename as basename3, dirname as dirname5, join as join6, resolve as resolve4 } from "node:path";
|
|
1536
|
+
function errorCode(error) {
|
|
1537
|
+
return error && typeof error === "object" && "code" in error ? String(error.code) : void 0;
|
|
1538
|
+
}
|
|
1539
|
+
async function syncDirectory(path) {
|
|
1540
|
+
try {
|
|
1541
|
+
const handle = await open3(path, "r");
|
|
1542
|
+
try {
|
|
1543
|
+
await handle.sync();
|
|
1544
|
+
} finally {
|
|
1545
|
+
await handle.close();
|
|
1546
|
+
}
|
|
1547
|
+
} catch {
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function lockOwnerIsAlive(raw) {
|
|
1551
|
+
const pid = Number.parseInt(raw.split(/\s+/, 1)[0] ?? "", 10);
|
|
1552
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
1553
|
+
return false;
|
|
1554
|
+
try {
|
|
1555
|
+
process.kill(pid, 0);
|
|
1556
|
+
return true;
|
|
1557
|
+
} catch (error) {
|
|
1558
|
+
return errorCode(error) === "EPERM";
|
|
1559
|
+
}
|
|
1560
|
+
}
|
|
1561
|
+
async function removeStaleLock(lockPath, staleMs = LOCK_STALE_MS) {
|
|
1562
|
+
const info = await lstat5(lockPath);
|
|
1563
|
+
if (!info.isDirectory()) {
|
|
1564
|
+
throw new Error(`Refusing unsafe non-directory installer lock ${lockPath}`);
|
|
1565
|
+
}
|
|
1566
|
+
if (Date.now() - info.mtimeMs <= staleMs)
|
|
1567
|
+
return false;
|
|
1568
|
+
const entries = await readdir3(lockPath);
|
|
1569
|
+
if (entries.length === 0) {
|
|
1570
|
+
try {
|
|
1571
|
+
await rmdir(lockPath);
|
|
1572
|
+
return true;
|
|
1573
|
+
} catch (error) {
|
|
1574
|
+
if (["ENOENT", "ENOTEMPTY"].includes(errorCode(error) ?? ""))
|
|
1575
|
+
return false;
|
|
1576
|
+
throw error;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
const [entry] = entries;
|
|
1580
|
+
if (entries.length !== 1 || entry === void 0 || !entry.startsWith("owner-"))
|
|
1581
|
+
return false;
|
|
1582
|
+
const tokenPath = join6(lockPath, entry);
|
|
1583
|
+
const owner = await readFile4(tokenPath, "utf8");
|
|
1584
|
+
if (lockOwnerIsAlive(owner))
|
|
1585
|
+
return false;
|
|
1586
|
+
try {
|
|
1587
|
+
await unlink(tokenPath);
|
|
1588
|
+
} catch (error) {
|
|
1589
|
+
if (errorCode(error) === "ENOENT")
|
|
1590
|
+
return false;
|
|
1591
|
+
throw error;
|
|
1592
|
+
}
|
|
1593
|
+
try {
|
|
1594
|
+
await rmdir(lockPath);
|
|
1595
|
+
return true;
|
|
1596
|
+
} catch (error) {
|
|
1597
|
+
if (["ENOENT", "ENOTEMPTY"].includes(errorCode(error) ?? ""))
|
|
1598
|
+
return false;
|
|
1599
|
+
throw error;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
async function acquireLock(lockPath, options = {}) {
|
|
1603
|
+
await mkdir2(dirname5(lockPath), { recursive: true });
|
|
1604
|
+
const owner = `${process.pid} ${Date.now()} ${randomBytes(12).toString("hex")}
|
|
1605
|
+
`;
|
|
1606
|
+
for (let attempt = 0; attempt < (options.retries ?? LOCK_RETRIES); attempt += 1) {
|
|
1607
|
+
try {
|
|
1608
|
+
await mkdir2(lockPath, { mode: 448 });
|
|
1609
|
+
const tokenPath = join6(lockPath, `owner-${process.pid}-${randomBytes(12).toString("hex")}`);
|
|
1610
|
+
const handle = await open3(tokenPath, "wx", 384);
|
|
1611
|
+
try {
|
|
1612
|
+
await handle.writeFile(owner, "utf8");
|
|
1613
|
+
await handle.sync();
|
|
1614
|
+
} finally {
|
|
1615
|
+
await handle.close();
|
|
1616
|
+
}
|
|
1617
|
+
await syncDirectory(lockPath);
|
|
1618
|
+
await syncDirectory(dirname5(lockPath));
|
|
1619
|
+
return tokenPath;
|
|
1620
|
+
} catch (error) {
|
|
1621
|
+
if (errorCode(error) !== "EEXIST") {
|
|
1622
|
+
await rmdir(lockPath).catch(() => void 0);
|
|
1623
|
+
if (errorCode(error) === "ENOENT")
|
|
1624
|
+
continue;
|
|
1625
|
+
throw error;
|
|
1626
|
+
}
|
|
1627
|
+
try {
|
|
1628
|
+
if (await removeStaleLock(lockPath, options.staleMs))
|
|
1629
|
+
continue;
|
|
1630
|
+
} catch (inspectError) {
|
|
1631
|
+
if (errorCode(inspectError) === "ENOENT")
|
|
1632
|
+
continue;
|
|
1633
|
+
throw inspectError;
|
|
1634
|
+
}
|
|
1635
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, options.retryMs ?? LOCK_RETRY_MS));
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
throw new Error(`Timed out waiting for installer lock ${lockPath}`);
|
|
1639
|
+
}
|
|
1640
|
+
async function withFileLock(lockPath, action, options) {
|
|
1641
|
+
const tokenPath = await acquireLock(lockPath, options);
|
|
1642
|
+
try {
|
|
1643
|
+
return await action();
|
|
1644
|
+
} finally {
|
|
1645
|
+
try {
|
|
1646
|
+
await unlink(tokenPath);
|
|
1647
|
+
await rmdir(lockPath);
|
|
1648
|
+
await syncDirectory(dirname5(lockPath));
|
|
1649
|
+
} catch {
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
var LOCK_STALE_MS, LOCK_RETRIES, LOCK_RETRY_MS;
|
|
1654
|
+
var init_settingsIo = __esm({
|
|
1655
|
+
"packages/shared/dist/settingsIo.js"() {
|
|
1656
|
+
"use strict";
|
|
1657
|
+
LOCK_STALE_MS = 12e4;
|
|
1658
|
+
LOCK_RETRIES = 100;
|
|
1659
|
+
LOCK_RETRY_MS = 20;
|
|
1660
|
+
}
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
// packages/shared/dist/hookConversation.js
|
|
1664
|
+
import { createHash as createHash4, randomBytes as randomBytes2 } from "node:crypto";
|
|
1665
|
+
import { constants as constants3 } from "node:fs";
|
|
1666
|
+
import { lstat as lstat6, mkdir as mkdir3, open as open4, rename as rename3, rm as rm3, utimes } from "node:fs/promises";
|
|
1667
|
+
import { dirname as dirname6 } from "node:path";
|
|
1668
|
+
function boundedHandle(value) {
|
|
1669
|
+
return typeof value === "string" && /^cv1\.[0-9a-f-]{36}\.[A-Za-z0-9_-]{43}$/.test(value);
|
|
1670
|
+
}
|
|
1671
|
+
async function configureHookConversation(input) {
|
|
1672
|
+
active = new HookConversation(input);
|
|
1673
|
+
await active.load();
|
|
1674
|
+
}
|
|
1675
|
+
function currentConversationId() {
|
|
1676
|
+
return active?.id;
|
|
1677
|
+
}
|
|
1678
|
+
function conversationMarker() {
|
|
1679
|
+
return active?.id ? `<system-reminder>mnemonik-conversation: ${active.id}</system-reminder>` : void 0;
|
|
1680
|
+
}
|
|
1681
|
+
async function adoptHookConversation(result) {
|
|
1682
|
+
await active?.adopt(result);
|
|
1683
|
+
}
|
|
1684
|
+
function withHookConversation(url, init, post) {
|
|
1685
|
+
return active ? active.request(url, init, post) : post(init);
|
|
1686
|
+
}
|
|
1687
|
+
var RETENTION_MS, CONVERSATION_STATE_FILE, HookConversation, active;
|
|
1688
|
+
var init_hookConversation = __esm({
|
|
1689
|
+
"packages/shared/dist/hookConversation.js"() {
|
|
1690
|
+
"use strict";
|
|
1691
|
+
init_settingsIo();
|
|
1692
|
+
init_runtimeSigners();
|
|
1693
|
+
RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
1694
|
+
CONVERSATION_STATE_FILE = "conversation.json";
|
|
1695
|
+
HookConversation = class {
|
|
1696
|
+
input;
|
|
1697
|
+
conversationId;
|
|
1698
|
+
scope;
|
|
1699
|
+
constructor(input) {
|
|
1700
|
+
this.input = input;
|
|
1701
|
+
this.scope = createHash4("sha256").update(JSON.stringify([
|
|
1702
|
+
input.server.replace(/\/$/, ""),
|
|
1703
|
+
input.account,
|
|
1704
|
+
input.host,
|
|
1705
|
+
input.nativeSessionId,
|
|
1706
|
+
input.agentId ?? ""
|
|
1707
|
+
])).digest("hex");
|
|
1708
|
+
}
|
|
1709
|
+
get id() {
|
|
1710
|
+
return this.conversationId;
|
|
1711
|
+
}
|
|
1712
|
+
async load() {
|
|
1713
|
+
this.conversationId = void 0;
|
|
1714
|
+
try {
|
|
1715
|
+
const directory = await lstat6(dirname6(this.input.stateFile));
|
|
1716
|
+
if (!directory.isDirectory() || directory.isSymbolicLink() || process.platform !== "win32" && (process.getuid && directory.uid !== process.getuid() || directory.mode & 63))
|
|
1717
|
+
return;
|
|
1718
|
+
const file = await open4(this.input.stateFile, constants3.O_RDONLY | constants3.O_NOFOLLOW);
|
|
1719
|
+
try {
|
|
1720
|
+
const stat2 = await file.stat();
|
|
1721
|
+
if (!stat2.isFile() || stat2.size > 4096 || process.platform !== "win32" && (process.getuid && stat2.uid !== process.getuid() || stat2.mode & 63))
|
|
1722
|
+
return;
|
|
1723
|
+
const cache = JSON.parse(await file.readFile("utf8"));
|
|
1724
|
+
if (cache.scope !== this.scope || !boundedHandle(cache.conversationId) || typeof cache.usedAt !== "number" || Date.now() - stat2.mtimeMs >= RETENTION_MS)
|
|
1725
|
+
return;
|
|
1726
|
+
this.conversationId = cache.conversationId;
|
|
1727
|
+
} finally {
|
|
1728
|
+
await file.close();
|
|
1729
|
+
}
|
|
1730
|
+
await utimes(this.input.stateFile, /* @__PURE__ */ new Date(), /* @__PURE__ */ new Date());
|
|
1731
|
+
return this.conversationId;
|
|
1732
|
+
} catch {
|
|
1733
|
+
return void 0;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
async locked(run) {
|
|
1737
|
+
const directory = dirname6(this.input.stateFile);
|
|
1738
|
+
await mkdir3(directory, { recursive: true, mode: 448 });
|
|
1739
|
+
const stat2 = await lstat6(directory);
|
|
1740
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink() || process.platform !== "win32" && (process.getuid && stat2.uid !== process.getuid() || stat2.mode & 63))
|
|
1741
|
+
throw new Error("conversation cache unavailable");
|
|
1742
|
+
ensureWindowsPrivateDirectorySync(directory);
|
|
1743
|
+
return withFileLock(`${this.input.stateFile}.lock`, run, {
|
|
1744
|
+
staleMs: 1e4,
|
|
1745
|
+
retries: 150,
|
|
1746
|
+
retryMs: 20
|
|
1747
|
+
});
|
|
1748
|
+
}
|
|
1749
|
+
async save(id) {
|
|
1750
|
+
const temporary = `${this.input.stateFile}.${randomBytes2(8).toString("hex")}`;
|
|
1751
|
+
const file = await open4(temporary, constants3.O_CREAT | constants3.O_EXCL | constants3.O_WRONLY | constants3.O_NOFOLLOW, 384);
|
|
1752
|
+
try {
|
|
1753
|
+
await file.writeFile(JSON.stringify({ v: 1, scope: this.scope, conversationId: id, usedAt: Date.now() }));
|
|
1754
|
+
} finally {
|
|
1755
|
+
await file.close();
|
|
1756
|
+
}
|
|
1757
|
+
try {
|
|
1758
|
+
await rename3(temporary, this.input.stateFile);
|
|
1759
|
+
this.conversationId = id;
|
|
1760
|
+
} finally {
|
|
1761
|
+
await rm3(temporary, { force: true });
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
/** Existing authenticated response is the acquisition; no additional endpoint. */
|
|
1765
|
+
async request(url, init, post) {
|
|
1766
|
+
if (typeof init.body !== "string" || !url.startsWith(`${this.input.server.replace(/\/$/, "")}/api/v1/`))
|
|
1767
|
+
return post(init);
|
|
1768
|
+
let body;
|
|
1769
|
+
try {
|
|
1770
|
+
body = JSON.parse(init.body);
|
|
1771
|
+
} catch {
|
|
1772
|
+
return post(init);
|
|
1773
|
+
}
|
|
1774
|
+
const acquisition = this.input.acquire !== false && (url.endsWith("/hooks/mcp-precheck") || url.endsWith("/hooks/injections") && ["SessionStart", "SubagentStart", "UserPromptSubmit"].includes(String(body.event)));
|
|
1775
|
+
const send = async () => {
|
|
1776
|
+
await this.load();
|
|
1777
|
+
const response = await post({
|
|
1778
|
+
...init,
|
|
1779
|
+
body: JSON.stringify({
|
|
1780
|
+
...body,
|
|
1781
|
+
...this.conversationId ? { conversationId: this.conversationId } : {}
|
|
1782
|
+
})
|
|
1783
|
+
});
|
|
1784
|
+
if (acquisition && response.ok) {
|
|
1785
|
+
const result = await response.clone().json().catch(() => null);
|
|
1786
|
+
if (boundedHandle(result?.conversationId)) {
|
|
1787
|
+
if (this.conversationId && this.conversationId !== result.conversationId)
|
|
1788
|
+
throw new Error("conversation response mismatch");
|
|
1789
|
+
await this.save(result.conversationId);
|
|
1790
|
+
}
|
|
1791
|
+
} else if (this.conversationId)
|
|
1792
|
+
await this.save(this.conversationId);
|
|
1793
|
+
return response;
|
|
1794
|
+
};
|
|
1795
|
+
return acquisition ? this.locked(send) : send();
|
|
1796
|
+
}
|
|
1797
|
+
/** Grok adopts only an authenticated explicit-bootstrap tool result. */
|
|
1798
|
+
async adopt(result) {
|
|
1799
|
+
const walk = (value, depth) => {
|
|
1800
|
+
if (depth > 5 || !value)
|
|
1801
|
+
return;
|
|
1802
|
+
if (typeof value === "string" && value.length < 65536) {
|
|
1803
|
+
const marker = value.match(/(?:^|[\s>])mnemonik-conversation:\s*(cv1\.[0-9a-f-]{36}\.[A-Za-z0-9_-]{43})(?=$|[\s<])/);
|
|
1804
|
+
if (marker && boundedHandle(marker[1]))
|
|
1805
|
+
return marker[1];
|
|
1806
|
+
try {
|
|
1807
|
+
return walk(JSON.parse(value), depth + 1);
|
|
1808
|
+
} catch {
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
if (typeof value !== "object")
|
|
1813
|
+
return;
|
|
1814
|
+
const object = value;
|
|
1815
|
+
if (boundedHandle(object.conversationId))
|
|
1816
|
+
return object.conversationId;
|
|
1817
|
+
if (typeof object.text === "string" && object.text.length < 65536) {
|
|
1818
|
+
const id2 = walk(object.text, depth + 1);
|
|
1819
|
+
if (id2)
|
|
1820
|
+
return id2;
|
|
1821
|
+
}
|
|
1822
|
+
for (const key of ["structuredContent", "result", "content"]) {
|
|
1823
|
+
const nested = object[key];
|
|
1824
|
+
for (const child of Array.isArray(nested) ? nested : [nested]) {
|
|
1825
|
+
const id2 = walk(child, depth + 1);
|
|
1826
|
+
if (id2)
|
|
1827
|
+
return id2;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
return;
|
|
1831
|
+
};
|
|
1832
|
+
const id = walk(result, 0);
|
|
1833
|
+
if (id)
|
|
1834
|
+
await this.locked(async () => {
|
|
1835
|
+
await this.load();
|
|
1836
|
+
if (this.conversationId && this.conversationId !== id)
|
|
1837
|
+
throw new Error("conversation response mismatch");
|
|
1838
|
+
await this.save(id);
|
|
1839
|
+
});
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
});
|
|
1844
|
+
|
|
1532
1845
|
// packages/shared/dist/repositoryFingerprint.js
|
|
1533
1846
|
var repositoryFingerprint_exports = {};
|
|
1534
1847
|
__export(repositoryFingerprint_exports, {
|
|
@@ -1536,7 +1849,7 @@ __export(repositoryFingerprint_exports, {
|
|
|
1536
1849
|
canonicalizeRemote: () => canonicalizeRemote,
|
|
1537
1850
|
selectRemote: () => selectRemote
|
|
1538
1851
|
});
|
|
1539
|
-
import { createHash as
|
|
1852
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
1540
1853
|
import { domainToASCII } from "node:url";
|
|
1541
1854
|
function canonicalizeRemote(url, { providerRules = REPOSITORY_PROVIDER_RULES } = {}) {
|
|
1542
1855
|
if (controls.test(url))
|
|
@@ -1646,7 +1959,7 @@ function canonicalizeRemote(url, { providerRules = REPOSITORY_PROVIDER_RULES } =
|
|
|
1646
1959
|
const canonical = `repo-v1:${prefix}/${parsed.path}`;
|
|
1647
1960
|
return {
|
|
1648
1961
|
canonical,
|
|
1649
|
-
hash:
|
|
1962
|
+
hash: createHash5("sha256").update(canonical, "utf8").digest("hex"),
|
|
1650
1963
|
algorithmVersion: 1
|
|
1651
1964
|
};
|
|
1652
1965
|
}
|
|
@@ -1690,7 +2003,9 @@ var init_repositoryFingerprint = __esm({
|
|
|
1690
2003
|
// packages/shared/dist/hookRuntime.js
|
|
1691
2004
|
var hookRuntime_exports = {};
|
|
1692
2005
|
__export(hookRuntime_exports, {
|
|
2006
|
+
CONVERSATION_STATE_FILE: () => CONVERSATION_STATE_FILE,
|
|
1693
2007
|
HOOK_STDIN_MAX_BYTES: () => HOOK_STDIN_MAX_BYTES,
|
|
2008
|
+
HookConversation: () => HookConversation,
|
|
1694
2009
|
PROJECT_ENSURE_TIMEOUT_MS: () => PROJECT_ENSURE_TIMEOUT_MS,
|
|
1695
2010
|
PROJECT_SETUP_MANUAL: () => PROJECT_SETUP_MANUAL,
|
|
1696
2011
|
PROJECT_SETUP_RUNNING: () => PROJECT_SETUP_RUNNING,
|
|
@@ -1698,9 +2013,13 @@ __export(hookRuntime_exports, {
|
|
|
1698
2013
|
RuntimeError: () => RuntimeError,
|
|
1699
2014
|
RuntimeReader: () => RuntimeReader,
|
|
1700
2015
|
aclRecords: () => aclRecords,
|
|
2016
|
+
adoptHookConversation: () => adoptHookConversation,
|
|
1701
2017
|
auditWindowsPermissions: () => auditWindowsPermissions,
|
|
1702
2018
|
bindHookContext: () => bindHookContext,
|
|
1703
2019
|
clearProjectIdentityCache: () => clearProjectIdentityCache,
|
|
2020
|
+
configureHookConversation: () => configureHookConversation,
|
|
2021
|
+
conversationMarker: () => conversationMarker,
|
|
2022
|
+
currentConversationId: () => currentConversationId,
|
|
1704
2023
|
ensureWindowsPrivateDirectorySync: () => ensureWindowsPrivateDirectorySync,
|
|
1705
2024
|
execute: () => execute,
|
|
1706
2025
|
findProjectIdentity: () => findProjectIdentity,
|
|
@@ -1724,7 +2043,8 @@ __export(hookRuntime_exports, {
|
|
|
1724
2043
|
verifyWindowsPermission: () => verifyWindowsPermission,
|
|
1725
2044
|
verifyWindowsPermissionSync: () => verifyWindowsPermissionSync,
|
|
1726
2045
|
versionName: () => versionName,
|
|
1727
|
-
windowsCurrentAccountSync: () => windowsCurrentAccountSync
|
|
2046
|
+
windowsCurrentAccountSync: () => windowsCurrentAccountSync,
|
|
2047
|
+
withHookConversation: () => withHookConversation
|
|
1728
2048
|
});
|
|
1729
2049
|
import { stderr, stdin } from "node:process";
|
|
1730
2050
|
function clearProjectIdentityCache() {
|
|
@@ -1756,7 +2076,7 @@ async function findProjectIdentityDetailed(startCwd, options = {}) {
|
|
|
1756
2076
|
function readHookStdin(options = {}) {
|
|
1757
2077
|
const stream = options.stream ?? stdin;
|
|
1758
2078
|
const maxBytes = options.maxBytes ?? HOOK_STDIN_MAX_BYTES;
|
|
1759
|
-
return new Promise((
|
|
2079
|
+
return new Promise((resolve5) => {
|
|
1760
2080
|
const chunks = [];
|
|
1761
2081
|
let bytes = 0;
|
|
1762
2082
|
let settled = false;
|
|
@@ -1772,7 +2092,7 @@ function readHookStdin(options = {}) {
|
|
|
1772
2092
|
stream.pause();
|
|
1773
2093
|
stream.destroy?.();
|
|
1774
2094
|
}
|
|
1775
|
-
|
|
2095
|
+
resolve5(value);
|
|
1776
2096
|
};
|
|
1777
2097
|
const onData = (chunk) => {
|
|
1778
2098
|
const buffer = typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk;
|
|
@@ -1811,21 +2131,21 @@ async function postHookBoundJson(server, path, token, body) {
|
|
|
1811
2131
|
}
|
|
1812
2132
|
async function bindHookContext(input, familyId, hmac, post, options = {}) {
|
|
1813
2133
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
1814
|
-
const { constants:
|
|
1815
|
-
const { lstat:
|
|
1816
|
-
const { dirname:
|
|
2134
|
+
const { constants: constants4 } = await import("node:fs");
|
|
2135
|
+
const { lstat: lstat7, mkdir: mkdir4, open: open5, realpath: realpath3 } = await import("node:fs/promises");
|
|
2136
|
+
const { dirname: dirname7 } = await import("node:path");
|
|
1817
2137
|
const { selectRemote: selectRemote2 } = await Promise.resolve().then(() => (init_repositoryFingerprint(), repositoryFingerprint_exports));
|
|
1818
|
-
const identity = await findProjectIdentityDetailed(await
|
|
2138
|
+
const identity = await findProjectIdentityDetailed(await realpath3(input.cwd));
|
|
1819
2139
|
if (identity.kind === "git_unavailable")
|
|
1820
2140
|
throw new Error("context unavailable");
|
|
1821
|
-
const root = await
|
|
2141
|
+
const root = await realpath3(identity.root);
|
|
1822
2142
|
const binding = await hmac(root);
|
|
1823
2143
|
const gitEnv = { LC_ALL: "C" };
|
|
1824
2144
|
for (const key2 of ["PATH", "HOME", "LANG", "SYSTEMROOT", "TEMP", "TMP", "USERPROFILE"])
|
|
1825
2145
|
if (process.env[key2] !== void 0)
|
|
1826
2146
|
gitEnv[key2] = process.env[key2];
|
|
1827
|
-
const git = (args) => new Promise((
|
|
1828
|
-
execFile3("git", args, { cwd: root, env: gitEnv, timeout: 2e3, encoding: "utf8" }, (error, stdout2) =>
|
|
2147
|
+
const git = (args) => new Promise((resolve5) => {
|
|
2148
|
+
execFile3("git", args, { cwd: root, env: gitEnv, timeout: 2e3, encoding: "utf8" }, (error, stdout2) => resolve5(error ? [] : stdout2.trim().split(/\r?\n/).filter(Boolean)));
|
|
1829
2149
|
});
|
|
1830
2150
|
const remotes = identity.repository.kind === "git" ? await git(["remote"]) : [];
|
|
1831
2151
|
const selection = selectRemote2(await Promise.all(remotes.map(async (name) => ({
|
|
@@ -1850,17 +2170,17 @@ async function bindHookContext(input, familyId, hmac, post, options = {}) {
|
|
|
1850
2170
|
...identity.kind === "ok" ? { projectId: identity.identity.projectId } : {}
|
|
1851
2171
|
};
|
|
1852
2172
|
const key = JSON.stringify([input.server, familyId, body]);
|
|
1853
|
-
const directory =
|
|
1854
|
-
for (const path of [
|
|
1855
|
-
const created = await
|
|
1856
|
-
const
|
|
1857
|
-
if (!
|
|
2173
|
+
const directory = dirname7(input.stateFile);
|
|
2174
|
+
for (const path of [dirname7(directory), directory]) {
|
|
2175
|
+
const created = await mkdir4(path, { recursive: true, mode: 448 });
|
|
2176
|
+
const stat2 = await lstat7(path);
|
|
2177
|
+
if (!stat2.isDirectory() || stat2.isSymbolicLink() || (options.platform ?? process.platform) !== "win32" && (process.getuid && stat2.uid !== process.getuid() || stat2.mode & 63))
|
|
1858
2178
|
throw new Error("cache unavailable");
|
|
1859
2179
|
if ((options.platform ?? process.platform) === "win32") {
|
|
1860
2180
|
await protectWindowsDirectory(path, created !== void 0, options.run, directory);
|
|
1861
2181
|
}
|
|
1862
2182
|
}
|
|
1863
|
-
const file = await
|
|
2183
|
+
const file = await open5(input.stateFile, constants4.O_CREAT | constants4.O_RDWR | constants4.O_NOFOLLOW, 384);
|
|
1864
2184
|
try {
|
|
1865
2185
|
let cache;
|
|
1866
2186
|
try {
|
|
@@ -1900,6 +2220,7 @@ var init_hookRuntime = __esm({
|
|
|
1900
2220
|
init_runtimeReader();
|
|
1901
2221
|
init_runtimeSigners();
|
|
1902
2222
|
init_projectSetupHandoff();
|
|
2223
|
+
init_hookConversation();
|
|
1903
2224
|
identityCache = /* @__PURE__ */ new Map();
|
|
1904
2225
|
HOOK_STDIN_MAX_BYTES = 1048576;
|
|
1905
2226
|
mismatchEmitted = false;
|
|
@@ -1909,7 +2230,9 @@ var init_hookRuntime = __esm({
|
|
|
1909
2230
|
// packages/cli/src/runtime/signers.ts
|
|
1910
2231
|
init_hookRuntime();
|
|
1911
2232
|
export {
|
|
2233
|
+
CONVERSATION_STATE_FILE,
|
|
1912
2234
|
HOOK_STDIN_MAX_BYTES,
|
|
2235
|
+
HookConversation,
|
|
1913
2236
|
PROJECT_ENSURE_TIMEOUT_MS,
|
|
1914
2237
|
PROJECT_SETUP_MANUAL,
|
|
1915
2238
|
PROJECT_SETUP_RUNNING,
|
|
@@ -1917,9 +2240,13 @@ export {
|
|
|
1917
2240
|
RuntimeError,
|
|
1918
2241
|
RuntimeReader,
|
|
1919
2242
|
aclRecords,
|
|
2243
|
+
adoptHookConversation,
|
|
1920
2244
|
auditWindowsPermissions,
|
|
1921
2245
|
bindHookContext,
|
|
1922
2246
|
clearProjectIdentityCache,
|
|
2247
|
+
configureHookConversation,
|
|
2248
|
+
conversationMarker,
|
|
2249
|
+
currentConversationId,
|
|
1923
2250
|
ensureWindowsPrivateDirectorySync,
|
|
1924
2251
|
execute,
|
|
1925
2252
|
findProjectIdentity,
|
|
@@ -1943,5 +2270,6 @@ export {
|
|
|
1943
2270
|
verifyWindowsPermission,
|
|
1944
2271
|
verifyWindowsPermissionSync,
|
|
1945
2272
|
versionName,
|
|
1946
|
-
windowsCurrentAccountSync
|
|
2273
|
+
windowsCurrentAccountSync,
|
|
2274
|
+
withHookConversation
|
|
1947
2275
|
};
|
package/dist/runtime/store.js
CHANGED
|
@@ -824,6 +824,24 @@ process.stdin.on('end', () => {
|
|
|
824
824
|
}
|
|
825
825
|
});
|
|
826
826
|
|
|
827
|
+
// packages/shared/dist/settingsIo.js
|
|
828
|
+
var init_settingsIo = __esm({
|
|
829
|
+
"packages/shared/dist/settingsIo.js"() {
|
|
830
|
+
"use strict";
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
// packages/shared/dist/hookConversation.js
|
|
835
|
+
var RETENTION_MS;
|
|
836
|
+
var init_hookConversation = __esm({
|
|
837
|
+
"packages/shared/dist/hookConversation.js"() {
|
|
838
|
+
"use strict";
|
|
839
|
+
init_settingsIo();
|
|
840
|
+
init_runtimeSigners();
|
|
841
|
+
RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
842
|
+
}
|
|
843
|
+
});
|
|
844
|
+
|
|
827
845
|
// packages/shared/dist/hookRuntime.js
|
|
828
846
|
var init_hookRuntime = __esm({
|
|
829
847
|
"packages/shared/dist/hookRuntime.js"() {
|
|
@@ -834,6 +852,7 @@ var init_hookRuntime = __esm({
|
|
|
834
852
|
init_runtimeReader();
|
|
835
853
|
init_runtimeSigners();
|
|
836
854
|
init_projectSetupHandoff();
|
|
855
|
+
init_hookConversation();
|
|
837
856
|
}
|
|
838
857
|
});
|
|
839
858
|
|