@mnemonik/cli 7.140.0 → 7.140.2

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.
Files changed (59) hide show
  1. package/dist/auth/credentials.js +40 -7
  2. package/dist/auth/index.js +40 -7
  3. package/dist/diagnostics.js +40 -7
  4. package/dist/digests.json +57 -53
  5. package/dist/help.d.ts.map +1 -1
  6. package/dist/help.js +50 -4
  7. package/dist/help.js.map +1 -1
  8. package/dist/hooksLog.d.ts +61 -0
  9. package/dist/hooksLog.d.ts.map +1 -0
  10. package/dist/hooksLog.js +350 -0
  11. package/dist/hooksLog.js.map +1 -0
  12. package/dist/humanReason.d.ts.map +1 -1
  13. package/dist/humanReason.js +0 -3
  14. package/dist/humanReason.js.map +1 -1
  15. package/dist/identity/migrate.js +101 -68
  16. package/dist/install/journal.js +40 -7
  17. package/dist/install/journey.d.ts.map +1 -1
  18. package/dist/install/journey.js +40 -10
  19. package/dist/install/journey.js.map +1 -1
  20. package/dist/install/ownership.js +40 -7
  21. package/dist/install/transaction.d.ts.map +1 -1
  22. package/dist/install/transaction.js +41 -9
  23. package/dist/install/transaction.js.map +1 -1
  24. package/dist/install/ui.js +40 -7
  25. package/dist/installation.js +40 -7
  26. package/dist/launcher.js +40 -7
  27. package/dist/preflight.js +200 -163
  28. package/dist/project/eligibility.js +40 -7
  29. package/dist/project/records.js +40 -7
  30. package/dist/project.d.ts +34 -1
  31. package/dist/project.d.ts.map +1 -1
  32. package/dist/project.js +291 -230
  33. package/dist/project.js.map +1 -1
  34. package/dist/router.d.ts +8 -0
  35. package/dist/router.d.ts.map +1 -1
  36. package/dist/router.js +328 -177
  37. package/dist/router.js.map +1 -1
  38. package/dist/runtime/releaseSource.js +40 -7
  39. package/dist/runtime/selfUpdate.js +40 -7
  40. package/dist/runtime/signers.js +781 -174
  41. package/dist/runtime/store.js +28 -0
  42. package/dist/runtime/updateCheck.js +40 -7
  43. package/dist/sbom.json +21 -21
  44. package/dist/scanner/control.js +40 -7
  45. package/dist/scanner/discover.d.ts.map +1 -1
  46. package/dist/scanner/discover.js +210 -170
  47. package/dist/scanner/discover.js.map +1 -1
  48. package/dist/scanner/enable.d.ts.map +1 -1
  49. package/dist/scanner/enable.js +45 -8
  50. package/dist/scanner/enable.js.map +1 -1
  51. package/dist/scanner/picker.d.ts.map +1 -1
  52. package/dist/scanner/picker.js +11 -3
  53. package/dist/scanner/picker.js.map +1 -1
  54. package/dist/scanner/service.js +40 -7
  55. package/dist/scanner/update.js +40 -7
  56. package/dist/scanner-release.json +24 -24
  57. package/dist/status.js +40 -7
  58. package/dist/vendor/local-setup.js +43 -10
  59. package/package.json +31 -31
package/dist/project.js CHANGED
@@ -885,6 +885,116 @@ var require_ignore = __commonJS({
885
885
  }
886
886
  });
887
887
 
888
+ // packages/shared/dist/secretPatterns.js
889
+ var init_secretPatterns = __esm({
890
+ "packages/shared/dist/secretPatterns.js"() {
891
+ "use strict";
892
+ }
893
+ });
894
+
895
+ // packages/shared/dist/protectedPaths.js
896
+ var init_protectedPaths = __esm({
897
+ "packages/shared/dist/protectedPaths.js"() {
898
+ "use strict";
899
+ }
900
+ });
901
+
902
+ // packages/shared/dist/projectIdentityFile.js
903
+ import { lstat, readFile } from "node:fs/promises";
904
+ import { join } from "node:path";
905
+ function parseIdentityFile(text) {
906
+ let value;
907
+ try {
908
+ value = JSON.parse(text);
909
+ } catch (error) {
910
+ return { kind: "malformed", detail: `unparseable JSON: ${error.message}` };
911
+ }
912
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
913
+ return { kind: "malformed", detail: "identity file must contain a JSON object" };
914
+ }
915
+ const record = value;
916
+ if (record.schemaVersion !== 1) {
917
+ return { kind: "unknown_version", version: record.schemaVersion };
918
+ }
919
+ const unknownKey = Object.keys(record).find((key) => !IDENTITY_KEYS.has(key));
920
+ if (unknownKey)
921
+ return { kind: "malformed", detail: `unknown key "${unknownKey}"` };
922
+ if (!isCanonicalUuid(record.projectId)) {
923
+ return { kind: "malformed", detail: '"projectId" must be a canonical RFC 4122 UUID string' };
924
+ }
925
+ if ("projectName" in record && typeof record.projectName !== "string") {
926
+ return { kind: "malformed", detail: '"projectName" must be a string when present' };
927
+ }
928
+ if ("repositoryFingerprint" in record && (!record.repositoryFingerprint || typeof record.repositoryFingerprint !== "object" || Array.isArray(record.repositoryFingerprint))) {
929
+ return { kind: "malformed", detail: '"repositoryFingerprint" must be an object when present' };
930
+ }
931
+ const fingerprint = record.repositoryFingerprint;
932
+ const unknownFingerprintKey = fingerprint ? Object.keys(fingerprint).find((key) => !FINGERPRINT_KEYS.has(key)) : void 0;
933
+ if (unknownFingerprintKey) {
934
+ return {
935
+ kind: "malformed",
936
+ detail: `unknown repositoryFingerprint key "${unknownFingerprintKey}"`
937
+ };
938
+ }
939
+ if (fingerprint && (fingerprint.algorithmVersion !== 1 || typeof fingerprint.hash !== "string")) {
940
+ return {
941
+ kind: "malformed",
942
+ detail: '"repositoryFingerprint" must contain algorithmVersion 1 and a string hash'
943
+ };
944
+ }
945
+ const repositoryFingerprint2 = fingerprint ? { algorithmVersion: 1, hash: fingerprint.hash } : void 0;
946
+ return {
947
+ kind: "ok",
948
+ identity: {
949
+ schemaVersion: 1,
950
+ projectId: record.projectId,
951
+ ...record.projectName === void 0 ? {} : { projectName: record.projectName },
952
+ ...repositoryFingerprint2 ? { repositoryFingerprint: repositoryFingerprint2 } : {}
953
+ }
954
+ };
955
+ }
956
+ function isConfigurationOnly(text) {
957
+ try {
958
+ const value = JSON.parse(text);
959
+ return !!value && typeof value === "object" && !Array.isArray(value) && !("projectId" in value) && (!("schemaVersion" in value) || value.schemaVersion === 1);
960
+ } catch {
961
+ return false;
962
+ }
963
+ }
964
+ async function readIdentityFile(dir, options = {}) {
965
+ const path = join(dir, ".mnemonik.json");
966
+ try {
967
+ const stat = await lstat(path);
968
+ if (stat.isSymbolicLink())
969
+ return { kind: "malformed", detail: "symlink" };
970
+ if (!stat.isFile())
971
+ return { kind: "malformed", detail: "identity path is not a regular file" };
972
+ const text = await readFile(path, "utf8");
973
+ if ((options.selectedRoot || options.configurationOnlyAbsent) && isConfigurationOnly(text))
974
+ return { kind: "absent" };
975
+ return parseIdentityFile(text);
976
+ } catch (error) {
977
+ if (error.code === "ENOENT")
978
+ return { kind: "absent" };
979
+ return { kind: "malformed", detail: `cannot read identity file: ${error.message}` };
980
+ }
981
+ }
982
+ var CANONICAL_UUID, isCanonicalUuid, IDENTITY_KEYS, FINGERPRINT_KEYS;
983
+ var init_projectIdentityFile = __esm({
984
+ "packages/shared/dist/projectIdentityFile.js"() {
985
+ "use strict";
986
+ CANONICAL_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
987
+ isCanonicalUuid = (value) => typeof value === "string" && CANONICAL_UUID.test(value);
988
+ IDENTITY_KEYS = /* @__PURE__ */ new Set([
989
+ "schemaVersion",
990
+ "projectId",
991
+ "projectName",
992
+ "repositoryFingerprint"
993
+ ]);
994
+ FINGERPRINT_KEYS = /* @__PURE__ */ new Set(["algorithmVersion", "hash"]);
995
+ }
996
+ });
997
+
888
998
  // packages/shared/dist/hookTimeouts.js
889
999
  var init_hookTimeouts = __esm({
890
1000
  "packages/shared/dist/hookTimeouts.js"() {
@@ -893,7 +1003,7 @@ var init_hookTimeouts = __esm({
893
1003
  });
894
1004
 
895
1005
  // packages/shared/dist/runtimeSigners.js
896
- import { basename, dirname as dirname2, join as join2, resolve, sep, win32 } from "node:path";
1006
+ import { basename, dirname as dirname2, join as join3, resolve, sep, win32 } from "node:path";
897
1007
  import { execFile, execFileSync } from "node:child_process";
898
1008
  function windowsCommand(file) {
899
1009
  const root = process.env.SystemRoot;
@@ -1122,102 +1232,8 @@ var init_repositoryFingerprint = __esm({
1122
1232
  }
1123
1233
  });
1124
1234
 
1125
- // packages/shared/dist/projectIdentityFile.js
1126
- import { lstat, readFile } from "node:fs/promises";
1127
- import { join as join3 } from "node:path";
1128
- function parseIdentityFile(text) {
1129
- let value;
1130
- try {
1131
- value = JSON.parse(text);
1132
- } catch (error) {
1133
- return { kind: "malformed", detail: `unparseable JSON: ${error.message}` };
1134
- }
1135
- if (!value || typeof value !== "object" || Array.isArray(value)) {
1136
- return { kind: "malformed", detail: "identity file must contain a JSON object" };
1137
- }
1138
- const record = value;
1139
- if (record.schemaVersion !== 1) {
1140
- return { kind: "unknown_version", version: record.schemaVersion };
1141
- }
1142
- const unknownKey = Object.keys(record).find((key) => !IDENTITY_KEYS.has(key));
1143
- if (unknownKey)
1144
- return { kind: "malformed", detail: `unknown key "${unknownKey}"` };
1145
- if (!isCanonicalUuid(record.projectId)) {
1146
- return { kind: "malformed", detail: '"projectId" must be a canonical RFC 4122 UUID string' };
1147
- }
1148
- if ("projectName" in record && typeof record.projectName !== "string") {
1149
- return { kind: "malformed", detail: '"projectName" must be a string when present' };
1150
- }
1151
- if ("repositoryFingerprint" in record && (!record.repositoryFingerprint || typeof record.repositoryFingerprint !== "object" || Array.isArray(record.repositoryFingerprint))) {
1152
- return { kind: "malformed", detail: '"repositoryFingerprint" must be an object when present' };
1153
- }
1154
- const fingerprint = record.repositoryFingerprint;
1155
- const unknownFingerprintKey = fingerprint ? Object.keys(fingerprint).find((key) => !FINGERPRINT_KEYS.has(key)) : void 0;
1156
- if (unknownFingerprintKey) {
1157
- return {
1158
- kind: "malformed",
1159
- detail: `unknown repositoryFingerprint key "${unknownFingerprintKey}"`
1160
- };
1161
- }
1162
- if (fingerprint && (fingerprint.algorithmVersion !== 1 || typeof fingerprint.hash !== "string")) {
1163
- return {
1164
- kind: "malformed",
1165
- detail: '"repositoryFingerprint" must contain algorithmVersion 1 and a string hash'
1166
- };
1167
- }
1168
- const repositoryFingerprint2 = fingerprint ? { algorithmVersion: 1, hash: fingerprint.hash } : void 0;
1169
- return {
1170
- kind: "ok",
1171
- identity: {
1172
- schemaVersion: 1,
1173
- projectId: record.projectId,
1174
- ...record.projectName === void 0 ? {} : { projectName: record.projectName },
1175
- ...repositoryFingerprint2 ? { repositoryFingerprint: repositoryFingerprint2 } : {}
1176
- }
1177
- };
1178
- }
1179
- async function readIdentityFile(dir, options = {}) {
1180
- const path = join3(dir, ".mnemonik.json");
1181
- try {
1182
- const stat = await lstat(path);
1183
- if (stat.isSymbolicLink())
1184
- return { kind: "malformed", detail: "symlink" };
1185
- if (!stat.isFile())
1186
- return { kind: "malformed", detail: "identity path is not a regular file" };
1187
- const text = await readFile(path, "utf8");
1188
- if (options.selectedRoot) {
1189
- try {
1190
- const value = JSON.parse(text);
1191
- if (value && typeof value === "object" && !Array.isArray(value) && !("projectId" in value) && (!("schemaVersion" in value) || value.schemaVersion === 1))
1192
- return { kind: "absent" };
1193
- } catch {
1194
- }
1195
- }
1196
- return parseIdentityFile(text);
1197
- } catch (error) {
1198
- if (error.code === "ENOENT")
1199
- return { kind: "absent" };
1200
- return { kind: "malformed", detail: `cannot read identity file: ${error.message}` };
1201
- }
1202
- }
1203
- var CANONICAL_UUID, isCanonicalUuid, IDENTITY_KEYS, FINGERPRINT_KEYS;
1204
- var init_projectIdentityFile = __esm({
1205
- "packages/shared/dist/projectIdentityFile.js"() {
1206
- "use strict";
1207
- CANONICAL_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
1208
- isCanonicalUuid = (value) => typeof value === "string" && CANONICAL_UUID.test(value);
1209
- IDENTITY_KEYS = /* @__PURE__ */ new Set([
1210
- "schemaVersion",
1211
- "projectId",
1212
- "projectName",
1213
- "repositoryFingerprint"
1214
- ]);
1215
- FINGERPRINT_KEYS = /* @__PURE__ */ new Set(["algorithmVersion", "hash"]);
1216
- }
1217
- });
1218
-
1219
1235
  // packages/shared/dist/repositoryRoot.js
1220
- import { lstat as lstat2, readFile as readFile2 } from "node:fs/promises";
1236
+ import { lstat as lstat2, readFile as readFile2, realpath } from "node:fs/promises";
1221
1237
  import { execFile as execFile2 } from "node:child_process";
1222
1238
  import { homedir } from "node:os";
1223
1239
  import { dirname as dirname3, join as join4, resolve as resolve2 } from "node:path";
@@ -1268,7 +1284,7 @@ async function confirmedBoundaryAt(path) {
1268
1284
  async function boundariesBetween(cwd, root) {
1269
1285
  const boundaries = [];
1270
1286
  let directory = cwd;
1271
- while (directory !== root) {
1287
+ while (!samePath(directory, root)) {
1272
1288
  const boundary = await confirmedBoundaryAt(directory);
1273
1289
  if (boundary)
1274
1290
  boundaries.push(boundary);
@@ -1291,37 +1307,31 @@ async function containingRepository(root) {
1291
1307
  directory = parent;
1292
1308
  }
1293
1309
  }
1294
- async function canonicalBoundaryRoot(boundary) {
1295
- if (boundary.kind === "directory")
1296
- return boundary.path;
1297
- const pointer = /^gitdir:\s*(.+)\s*$/im.exec(await readFile2(join4(boundary.path, ".git"), "utf8"))?.[1];
1298
- if (!pointer)
1299
- return boundary.path;
1300
- const gitDir = resolve2(boundary.path, pointer);
1301
- try {
1302
- const commonDir = resolve2(gitDir, (await readFile2(join4(gitDir, "commondir"), "utf8")).trim());
1303
- return dirname3(commonDir);
1304
- } catch (error) {
1305
- if (error.code === "ENOENT")
1306
- return boundary.path;
1307
- throw error;
1308
- }
1310
+ async function canonicalPath(path) {
1311
+ const absolute = resolve2(path);
1312
+ return realpath(absolute).catch(() => absolute);
1313
+ }
1314
+ function samePath(left, right) {
1315
+ return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
1309
1316
  }
1310
1317
  async function resolveRepositoryRoot(cwd) {
1311
- const absoluteCwd = resolve2(cwd);
1318
+ const absoluteCwd = await canonicalPath(cwd);
1312
1319
  try {
1313
1320
  const { stdout } = await runGit(absoluteCwd, [
1314
1321
  "rev-parse",
1315
1322
  "--show-toplevel",
1323
+ "--git-dir",
1316
1324
  "--git-common-dir"
1317
1325
  ]);
1318
- const [rootLine, commonLine, ...extra] = stdout.trim().split(/\r?\n/);
1319
- if (!rootLine || !commonLine || extra.length) {
1326
+ const [rootLine, gitDirLine, commonLine, ...extra] = stdout.trim().split(/\r?\n/);
1327
+ if (!rootLine || !gitDirLine || !commonLine || extra.length) {
1320
1328
  return { kind: "git_unavailable", detail: "git rev-parse returned an unexpected response" };
1321
1329
  }
1322
- const root = resolve2(rootLine);
1323
- const commonDir = resolve2(root, commonLine);
1324
- const isLinkedWorktree = commonDir !== join4(root, ".git");
1330
+ const fromGit = (line) => canonicalPath(resolve2(absoluteCwd, line));
1331
+ const root = await fromGit(rootLine);
1332
+ const gitDir = await fromGit(gitDirLine);
1333
+ const commonDir = await fromGit(commonLine);
1334
+ const isLinkedWorktree = !samePath(gitDir, commonDir);
1325
1335
  const nested = await boundariesBetween(absoluteCwd, root);
1326
1336
  if (!isLinkedWorktree && await containingRepository(root)) {
1327
1337
  const boundary = await boundaryAt(root);
@@ -1343,14 +1353,41 @@ async function resolveRepositoryRoot(cwd) {
1343
1353
  return { kind: "git_unavailable", detail: failure.message };
1344
1354
  }
1345
1355
  }
1356
+ async function linkedWorktreeCommonDir(dir) {
1357
+ try {
1358
+ if (!(await lstat2(join4(dir, ".git"))).isFile())
1359
+ return void 0;
1360
+ const pointer = /^gitdir:\s*(.+?)\s*$/im.exec(await readFile2(join4(dir, ".git"), "utf8"))?.[1];
1361
+ if (!pointer)
1362
+ return void 0;
1363
+ const gitDir = resolve2(dir, pointer);
1364
+ const common = (await readFile2(join4(gitDir, "commondir"), "utf8")).trim();
1365
+ return common ? await canonicalPath(resolve2(gitDir, common)) : void 0;
1366
+ } catch {
1367
+ return void 0;
1368
+ }
1369
+ }
1370
+ async function mainCheckout(worktreeTop, commonDir) {
1371
+ try {
1372
+ const { stdout } = await runGit(worktreeTop, ["worktree", "list", "--porcelain"]);
1373
+ const first = stdout.split(/\r?\n\r?\n/)[0] ?? "";
1374
+ const path = /^worktree (.+)$/m.exec(first)?.[1];
1375
+ if (path) {
1376
+ const main = await canonicalPath(resolve2(worktreeTop, path));
1377
+ return /^bare$/m.test(first) ? dirname3(main) : main;
1378
+ }
1379
+ } catch {
1380
+ }
1381
+ return dirname3(commonDir);
1382
+ }
1346
1383
  async function readPlainIdentity(start2) {
1347
- const home = resolve2(homedir());
1384
+ const home = await canonicalPath(homedir());
1348
1385
  let directory = start2;
1349
1386
  while (true) {
1350
- const result = await readIdentityFile(directory);
1387
+ const result = await readIdentityFile(directory, { configurationOnlyAbsent: true });
1351
1388
  if (result.kind !== "absent")
1352
1389
  return { root: directory, result };
1353
- if (directory === home)
1390
+ if (samePath(directory, home))
1354
1391
  break;
1355
1392
  const parent = dirname3(directory);
1356
1393
  if (parent === directory)
@@ -1359,58 +1396,72 @@ async function readPlainIdentity(start2) {
1359
1396
  }
1360
1397
  return { root: start2, result: { kind: "absent" } };
1361
1398
  }
1399
+ async function nearestIdentity(start2) {
1400
+ const home = await canonicalPath(homedir());
1401
+ let directory = start2;
1402
+ while (true) {
1403
+ const commonDir = await linkedWorktreeCommonDir(directory);
1404
+ if (commonDir)
1405
+ return { worktreeTop: directory, commonDir };
1406
+ const result = await readIdentityFile(directory, { configurationOnlyAbsent: true });
1407
+ if (result.kind !== "absent")
1408
+ return { root: directory, result };
1409
+ if (samePath(directory, home))
1410
+ return void 0;
1411
+ const parent = dirname3(directory);
1412
+ if (parent === directory)
1413
+ return void 0;
1414
+ directory = parent;
1415
+ }
1416
+ }
1417
+ async function resolveNearestProjectIdentity(cwd) {
1418
+ const start2 = await canonicalPath(cwd);
1419
+ const resolved = await resolveRepositoryRoot(start2);
1420
+ const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: start2 } : resolved;
1421
+ const nested = repository.kind === "git" ? repository.nested : [];
1422
+ let found = await nearestIdentity(start2);
1423
+ if (found && "worktreeTop" in found) {
1424
+ found = await readPlainIdentity(await mainCheckout(found.worktreeTop, found.commonDir));
1425
+ }
1426
+ if (found) {
1427
+ return shapedIdentity(found, await projectFolderRepository(found.root, repository), nested);
1428
+ }
1429
+ return { ...withBase(repository, repository.root, nested), kind: "absent" };
1430
+ }
1431
+ async function resolveNamedProjectIdentity(cwd, options) {
1432
+ const start2 = await canonicalPath(cwd);
1433
+ const resolved = await resolveRepositoryRoot(start2);
1434
+ const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: start2 } : resolved;
1435
+ const commonDir = await linkedWorktreeCommonDir(start2);
1436
+ const root = commonDir ? await mainCheckout(start2, commonDir) : start2;
1437
+ return shapedIdentity({ root, result: await readIdentityFile(root, options) }, await projectFolderRepository(root, repository), repository.kind === "git" ? repository.nested : []);
1438
+ }
1439
+ function shapedIdentity(found, repository, nested) {
1440
+ const base = withBase(repository, found.root, nested);
1441
+ if (found.result.kind === "ok")
1442
+ return { ...base, ...found.result };
1443
+ if (found.result.kind === "unknown_version")
1444
+ return { ...base, ...found.result, path: found.root };
1445
+ if (found.result.kind === "malformed")
1446
+ return { ...base, ...found.result, path: found.root };
1447
+ return { ...base, kind: "absent" };
1448
+ }
1449
+ async function projectFolderRepository(projectRoot, known) {
1450
+ if (known.kind === "git" && samePath(known.root, projectRoot))
1451
+ return known;
1452
+ const repository = await resolveRepositoryRoot(projectRoot);
1453
+ if (repository.kind === "git" && samePath(repository.root, projectRoot))
1454
+ return repository;
1455
+ return { kind: "plain", root: projectRoot };
1456
+ }
1362
1457
  function withBase(repository, root, nested) {
1363
1458
  return { root, repository, nested };
1364
1459
  }
1365
1460
  async function resolveProjectIdentity(cwd, options = {}) {
1366
- const resolved = await resolveRepositoryRoot(cwd);
1367
- const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: resolve2(cwd) } : resolved;
1368
- if (repository.kind === "plain") {
1369
- const { root, result } = options.selectedRoot ? { root: repository.root, result: await readIdentityFile(repository.root, options) } : await readPlainIdentity(repository.root);
1370
- const base2 = withBase(repository, root, []);
1371
- if (result.kind === "ok")
1372
- return { ...base2, ...result };
1373
- if (result.kind === "unknown_version")
1374
- return { ...base2, ...result, path: root };
1375
- if (result.kind === "malformed")
1376
- return { ...base2, ...result, path: root };
1377
- return { ...base2, kind: "absent" };
1378
- }
1379
- const ownRoot = repository.isLinkedWorktree ? dirname3(repository.commonDir) : repository.root;
1380
- const outer = repository.isLinkedWorktree ? void 0 : await containingRepository(repository.root);
1381
- const own = await readIdentityFile(ownRoot, options);
1382
- if (!outer || options.selectedRoot || own.kind === "ok") {
1383
- const base2 = withBase(repository, ownRoot, repository.nested);
1384
- if (own.kind === "ok")
1385
- return { ...base2, ...own };
1386
- if (own.kind === "unknown_version")
1387
- return { ...base2, ...own, path: ownRoot };
1388
- if (own.kind === "malformed")
1389
- return { ...base2, ...own, path: ownRoot };
1390
- return { ...base2, kind: "absent" };
1391
- }
1392
- const nested = repository.nested;
1393
- const parentRoot = await canonicalBoundaryRoot(outer);
1394
- const parent = await readIdentityFile(parentRoot);
1395
- const base = withBase(repository, parentRoot, nested);
1396
- if (own.kind === "unknown_version")
1397
- return { ...base, ...own, path: ownRoot };
1398
- if (own.kind === "malformed")
1399
- return { ...base, ...own, path: ownRoot };
1400
- if (parent.kind === "unknown_version")
1401
- return { ...base, ...parent, path: parentRoot };
1402
- if (parent.kind === "malformed")
1403
- return { ...base, ...parent, path: parentRoot };
1404
- if (!options.allowNestedInherit) {
1405
- return {
1406
- ...base,
1407
- kind: "nested",
1408
- ...parent.kind === "ok" ? { parentIdentity: parent.identity } : {}
1409
- };
1461
+ if (options.selectedRoot || options.namedRoot) {
1462
+ return resolveNamedProjectIdentity(cwd, { selectedRoot: options.selectedRoot });
1410
1463
  }
1411
- if (parent.kind === "ok")
1412
- return { ...base, kind: "ok", identity: parent.identity };
1413
- return { ...base, kind: "absent" };
1464
+ return resolveNearestProjectIdentity(cwd);
1414
1465
  }
1415
1466
  var GIT_TIMEOUT_MS, GIT_ENV_KEYS;
1416
1467
  var init_repositoryRoot = __esm({
@@ -1431,6 +1482,18 @@ var init_repositoryRoot = __esm({
1431
1482
  }
1432
1483
  });
1433
1484
 
1485
+ // packages/shared/dist/hookTrace.js
1486
+ var HOOK_TRACE_MAX_BYTES;
1487
+ var init_hookTrace = __esm({
1488
+ "packages/shared/dist/hookTrace.js"() {
1489
+ "use strict";
1490
+ init_protectedPaths();
1491
+ init_runtimeSigners();
1492
+ init_secretPatterns();
1493
+ HOOK_TRACE_MAX_BYTES = 2 * 1024 * 1024;
1494
+ }
1495
+ });
1496
+
1434
1497
  // packages/shared/dist/runtimeReader.js
1435
1498
  var RuntimeError;
1436
1499
  var init_runtimeReader = __esm({
@@ -1502,10 +1565,12 @@ var init_hookRuntime = __esm({
1502
1565
  init_runtimeSigners();
1503
1566
  init_hookTimeouts();
1504
1567
  init_repositoryRoot();
1568
+ init_hookTrace();
1505
1569
  init_runtimeReader();
1506
1570
  init_runtimeSigners();
1507
1571
  init_projectSetupHandoff();
1508
1572
  init_hookConversation();
1573
+ init_hookTrace();
1509
1574
  }
1510
1575
  });
1511
1576
 
@@ -3135,6 +3200,9 @@ var MCP_INSTRUCTIONS = getMcpInstructions();
3135
3200
 
3136
3201
  // packages/shared/dist/codeScanner.js
3137
3202
  var import_ignore = __toESM(require_ignore(), 1);
3203
+ init_secretPatterns();
3204
+ init_protectedPaths();
3205
+ init_projectIdentityFile();
3138
3206
 
3139
3207
  // node_modules/web-tree-sitter/web-tree-sitter.js
3140
3208
  var __defProp2 = Object.defineProperty;
@@ -7180,9 +7248,9 @@ var Query = class {
7180
7248
  };
7181
7249
 
7182
7250
  // packages/shared/dist/ast/grammars.js
7183
- import { dirname, extname, join } from "node:path";
7251
+ import { dirname, extname, join as join2 } from "node:path";
7184
7252
  import { fileURLToPath } from "node:url";
7185
- var WASM_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
7253
+ var WASM_DIR = join2(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
7186
7254
 
7187
7255
  // packages/shared/dist/ast/astChunker.js
7188
7256
  var MAX_AST_PARSE_BYTES = 2 * 1024 * 1024;
@@ -7360,6 +7428,7 @@ var BUILT_IN_IGNORE_DIR_SET = new Set(BUILT_IN_IGNORE_DIRS);
7360
7428
  var import_ignore2 = __toESM(require_ignore(), 1);
7361
7429
 
7362
7430
  // packages/shared/dist/index.js
7431
+ init_secretPatterns();
7363
7432
  init_hookTimeouts();
7364
7433
 
7365
7434
  // packages/shared/dist/jitDeliveryAck.js
@@ -7375,9 +7444,10 @@ init_settingsIo();
7375
7444
  init_repositoryFingerprint();
7376
7445
  init_projectIdentityFile();
7377
7446
  init_repositoryRoot();
7447
+ init_protectedPaths();
7378
7448
 
7379
7449
  // packages/local-setup/dist/index.js
7380
- import { realpath, unlink as unlink2 } from "node:fs/promises";
7450
+ import { realpath as realpath2, unlink as unlink2 } from "node:fs/promises";
7381
7451
  import { basename as basename2, dirname as dirname5, join as join7 } from "node:path";
7382
7452
 
7383
7453
  // packages/local-setup/dist/contracts.js
@@ -7677,13 +7747,13 @@ function createProjectSetupExecutor(deps) {
7677
7747
  let resolution = await deps.resolver.resolveProjectIdentity(options.cwd, options);
7678
7748
  if (resolution.kind !== "ok" && resolution.kind !== "absent")
7679
7749
  return actionRequired(resolution.kind);
7680
- const root = await realpath(resolution.root);
7750
+ const root = await realpath2(resolution.root);
7681
7751
  const path = recordPath(root, deps.stateDir);
7682
7752
  return withLock(path, deps.waitMs ?? 6e4, async (assertOwned) => {
7683
7753
  const fresh = await deps.resolver.resolveProjectIdentity(options.cwd, options);
7684
7754
  if (fresh.kind !== "ok" && fresh.kind !== "absent")
7685
7755
  return actionRequired(fresh.kind);
7686
- if (await realpath(fresh.root) !== root)
7756
+ if (await realpath2(fresh.root) !== root)
7687
7757
  return actionRequired("identity_changed");
7688
7758
  resolution = fresh;
7689
7759
  const file = join7(root, ".mnemonik.json");
@@ -7940,7 +8010,7 @@ function createProjectSetupExecutor(deps) {
7940
8010
  };
7941
8011
  }
7942
8012
  async function cancelProjectSetup(folder, stateDir, waitMs = 6e4) {
7943
- const root = await realpath(folder);
8013
+ const root = await realpath2(folder);
7944
8014
  const path = recordPath(root, stateDir);
7945
8015
  return withLock(path, waitMs, async (assertOwned) => {
7946
8016
  const saved = await readBytes(path);
@@ -8021,8 +8091,12 @@ function answerCommands(actions, root, details = {}) {
8021
8091
  return [];
8022
8092
  });
8023
8093
  }
8094
+ async function projectFolderFor(folder, resolver) {
8095
+ const resolution = await resolver.resolveProjectIdentity(folder);
8096
+ return resolution.kind === "absent" || resolution.kind === "git_unavailable" ? folder : resolution.root;
8097
+ }
8024
8098
  async function ensureProjectRoot(root, executor) {
8025
- return executor.ensureProject({ cwd: root, allowCreate: true, allowNestedInherit: false });
8099
+ return executor.ensureProject({ cwd: root, allowCreate: true, namedRoot: true });
8026
8100
  }
8027
8101
  var refusalReasons = {
8028
8102
  filesystem_root: "Mnemonik does not index a whole disk.",
@@ -8039,8 +8113,6 @@ var refusalReasons = {
8039
8113
  deleted: "Its project was deleted.",
8040
8114
  fingerprint_mismatch: "Its Git remote does not match the repository this project was set up with.",
8041
8115
  confirmation_required: "Mnemonik has not seen this folder on this machine before.",
8042
- nested: "It sits inside another project.",
8043
- conflict: "It holds project files that disagree.",
8044
8116
  invalid_identity: "Its project file cannot be read.",
8045
8117
  malformed: "Its project file cannot be read.",
8046
8118
  unknown_version: "Its project file was written by a newer version of Mnemonik.",
@@ -8078,8 +8150,6 @@ var refusalSteps = {
8078
8150
  identity_too_large: FRESH_FILE,
8079
8151
  fingerprint_mismatch: "Run mnemonik project link <project id> --confirm-mismatch in that folder to connect it anyway.",
8080
8152
  confirmation_required: "Run mnemonik project setup in that folder to confirm it.",
8081
- nested: "Run mnemonik project setup in that folder and choose which project it belongs to.",
8082
- conflict: "Run mnemonik project setup in that folder and choose which project it belongs to.",
8083
8153
  identity_changed: AGAIN,
8084
8154
  operation_context_changed: "Run mnemonik project setup --cancel in that folder, then run the command again.",
8085
8155
  rollback_in_progress: "Wait for it to finish, then run the command again.",
@@ -8116,7 +8186,7 @@ var connectedProjectsMessage = (roots) => roots.length === 1 ? ` \u2713 Connect
8116
8186
  var projectExecutor = (dependencies) => {
8117
8187
  const executor = createProjectSetupExecutor(dependencies);
8118
8188
  return {
8119
- resolveProjectIdentity: (cwd) => dependencies.resolver.resolveProjectIdentity(cwd, { allowNestedInherit: false }),
8189
+ resolveProjectIdentity: (cwd, options) => dependencies.resolver.resolveProjectIdentity(cwd, options),
8120
8190
  ...executor
8121
8191
  };
8122
8192
  };
@@ -8159,6 +8229,28 @@ async function repositoryFingerprint(root) {
8159
8229
  hash: selected.fingerprint.hash
8160
8230
  } : null;
8161
8231
  }
8232
+ async function rootIssueContext(root, dependencies) {
8233
+ const [binding, resolution] = await Promise.all([
8234
+ dependencies.hmacRootBinding(1, root),
8235
+ // The root is already chosen: read its own identity file, not a parent's.
8236
+ dependencies.resolveIdentity(root, { namedRoot: true })
8237
+ ]);
8238
+ const fingerprint = resolution.kind !== "git_unavailable" && resolution.repository.kind === "git" ? await (dependencies.fingerprint ?? repositoryFingerprint)(root) : null;
8239
+ const evidence = {
8240
+ deviceRootContext: {
8241
+ algorithmVersion: binding.version,
8242
+ hash: Buffer.from(binding.hmac, "base64url").toString("hex")
8243
+ },
8244
+ repositoryFingerprint: fingerprint
8245
+ };
8246
+ const context = {
8247
+ ...evidence,
8248
+ rootKind: resolution.kind !== "git_unavailable" && resolution.repository.kind === "plain" ? "selected_non_git" : resolution.kind === "git_unavailable" ? "ineligible" : "git",
8249
+ identityState: resolution.kind === "ok" ? "valid" : resolution.kind === "absent" ? "absent" : "invalid",
8250
+ ...resolution.kind === "ok" ? { projectId: resolution.identity.projectId } : {}
8251
+ };
8252
+ return { evidence, context };
8253
+ }
8162
8254
  async function createRealProjectRuntime(options = {}) {
8163
8255
  const resolveIdentity = (cwd, resolverOptions) => resolveProjectIdentity(cwd, { ...resolverOptions, selectedRoot: options.selectedRoots });
8164
8256
  const credentials = options.credentials ?? createCliCredentials(options.stateDir ? { stateDir: options.stateDir } : {});
@@ -8185,24 +8277,10 @@ async function createRealProjectRuntime(options = {}) {
8185
8277
  });
8186
8278
  const account = await transport.accountContext();
8187
8279
  const bindContext = async (root) => {
8188
- const [binding, fingerprint, resolution] = await Promise.all([
8189
- credentials.hmacRootBinding(1, root),
8190
- repositoryFingerprint(root),
8191
- resolveIdentity(root, { allowNestedInherit: false })
8192
- ]);
8193
- const evidence = {
8194
- deviceRootContext: {
8195
- algorithmVersion: binding.version,
8196
- hash: Buffer.from(binding.hmac, "base64url").toString("hex")
8197
- },
8198
- repositoryFingerprint: fingerprint
8199
- };
8200
- const context = {
8201
- ...evidence,
8202
- rootKind: resolution.kind !== "git_unavailable" && resolution.repository.kind === "plain" ? "selected_non_git" : resolution.kind === "git_unavailable" ? "ineligible" : "git",
8203
- identityState: resolution.kind === "ok" ? "valid" : resolution.kind === "absent" ? "absent" : "invalid",
8204
- ...resolution.kind === "ok" ? { projectId: resolution.identity.projectId } : {}
8205
- };
8280
+ const { evidence, context } = await rootIssueContext(root, {
8281
+ hmacRootBinding: (version, path) => credentials.hmacRootBinding(version, path),
8282
+ resolveIdentity
8283
+ });
8206
8284
  contexts.set(contextKey(evidence), context);
8207
8285
  return evidence;
8208
8286
  };
@@ -8351,9 +8429,10 @@ async function finishRequired(deps, input, root, reason, owner, state, allowedAc
8351
8429
  }
8352
8430
  async function statusCommand(input, deps) {
8353
8431
  const cwd = input.path ?? deps.cwd;
8354
- const resolution = await (deps.resolver?.resolveProjectIdentity ?? resolveProjectIdentity)(cwd, {
8355
- allowNestedInherit: false
8356
- });
8432
+ const resolution = await (deps.resolver?.resolveProjectIdentity ?? resolveProjectIdentity)(
8433
+ cwd,
8434
+ {}
8435
+ );
8357
8436
  const root = "root" in resolution ? resolution.root : cwd;
8358
8437
  const projectId = resolution.kind === "ok" ? resolution.identity.projectId : null;
8359
8438
  const currentHash = await identityHash(root);
@@ -8395,7 +8474,7 @@ async function statusCommand(input, deps) {
8395
8474
  }
8396
8475
  async function cancelCommand(input, deps) {
8397
8476
  const cwd = input.path ?? deps.cwd;
8398
- const resolution = await (deps.executor ?? deps.resolver ?? { resolveProjectIdentity }).resolveProjectIdentity(cwd, { allowNestedInherit: false });
8477
+ const resolution = await (deps.executor ?? deps.resolver ?? { resolveProjectIdentity }).resolveProjectIdentity(cwd, { namedRoot: input.path !== void 0 });
8399
8478
  const result = await cancelProjectSetup(
8400
8479
  "root" in resolution ? resolution.root : cwd,
8401
8480
  deps.stateDir
@@ -8428,29 +8507,11 @@ async function runProjectCommandInner(input, deps, prompts) {
8428
8507
  allowedActions: ["choose_personal_or_team_owner", "cancel"]
8429
8508
  });
8430
8509
  const cwd = input.path ?? deps.cwd;
8431
- const resolution = await executor.resolveProjectIdentity(cwd);
8432
- if (resolution.kind === "nested" || resolution.kind === "conflict") {
8433
- const identityLocation = join8(resolution.root, ".mnemonik.json");
8434
- if (!input.json) {
8435
- deps.output.line(`Root: ${resolution.root}`);
8436
- deps.output.line(`Identity: ${identityLocation}`);
8437
- }
8438
- return finishRequired(
8439
- deps,
8440
- input,
8441
- resolution.root,
8442
- resolution.kind,
8443
- owner,
8444
- resolution.kind,
8445
- [
8446
- "use_parent_identity",
8447
- "initialize_nested_separately",
8448
- "select_main_or_worktree_identity",
8449
- "cancel"
8450
- ],
8451
- { identityLocation }
8452
- );
8453
- }
8510
+ const named = input.path !== void 0;
8511
+ const resolution = await executor.resolveProjectIdentity(
8512
+ cwd,
8513
+ named ? { namedRoot: true } : void 0
8514
+ );
8454
8515
  const decision = await evaluateRoot(resolution, { cwd, home: deps.home });
8455
8516
  if (!decision.allowed) {
8456
8517
  if (!input.json)
@@ -8467,7 +8528,7 @@ async function runProjectCommandInner(input, deps, prompts) {
8467
8528
  cwd,
8468
8529
  owner,
8469
8530
  allowCreate: input.command !== "link",
8470
- allowNestedInherit: false
8531
+ ...named ? { namedRoot: true } : {}
8471
8532
  };
8472
8533
  if (input.command === "setup") {
8473
8534
  if ((input.nonInteractive || input.json) && !input.apply) {
@@ -8686,8 +8747,7 @@ async function ensureProjectForAgent(options) {
8686
8747
  }
8687
8748
  const result = await executor.ensureProject({
8688
8749
  cwd: options.cwd,
8689
- allowCreate: true,
8690
- allowNestedInherit: false
8750
+ allowCreate: true
8691
8751
  });
8692
8752
  options.output.json(result);
8693
8753
  return result.status === "ACTION_REQUIRED" || result.status === "project_setup_required" ? 3 : 0;
@@ -8696,8 +8756,7 @@ async function rollbackProjectIdentity(options) {
8696
8756
  if (!options.executor) return 3;
8697
8757
  const result = await options.executor.rollback({
8698
8758
  cwd: options.cwd,
8699
- allowCreate: false,
8700
- allowNestedInherit: false
8759
+ allowCreate: false
8701
8760
  });
8702
8761
  options.output.json(result);
8703
8762
  return result.status === "rolled_back" ? 0 : 3;
@@ -8712,8 +8771,10 @@ export {
8712
8771
  folderRefusalMessage,
8713
8772
  hasRefusalWords,
8714
8773
  projectExecutor,
8774
+ projectFolderFor,
8715
8775
  projectLimitMessage,
8716
8776
  repositoryFingerprint,
8717
8777
  rollbackProjectIdentity,
8778
+ rootIssueContext,
8718
8779
  runProjectCommand
8719
8780
  };