@mnemonik/cli 7.140.1 → 7.140.3

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 (73) hide show
  1. package/dist/auth/credentials.js +41 -8
  2. package/dist/auth/index.js +41 -8
  3. package/dist/auth/installSession.js +1 -1
  4. package/dist/auth/status.js +1 -1
  5. package/dist/authorizationWords.js +1 -1
  6. package/dist/diagnostics.js +41 -8
  7. package/dist/digests.json +71 -67
  8. package/dist/help.d.ts.map +1 -1
  9. package/dist/help.js +50 -4
  10. package/dist/help.js.map +1 -1
  11. package/dist/hooksLog.d.ts +61 -0
  12. package/dist/hooksLog.d.ts.map +1 -0
  13. package/dist/hooksLog.js +350 -0
  14. package/dist/hooksLog.js.map +1 -0
  15. package/dist/humanReason.d.ts +7 -0
  16. package/dist/humanReason.d.ts.map +1 -1
  17. package/dist/humanReason.js +12 -4
  18. package/dist/humanReason.js.map +1 -1
  19. package/dist/identity/migrate.js +102 -69
  20. package/dist/install/hosts.js +1 -1
  21. package/dist/install/journal.js +41 -8
  22. package/dist/install/journey.d.ts.map +1 -1
  23. package/dist/install/journey.js +41 -11
  24. package/dist/install/journey.js.map +1 -1
  25. package/dist/install/ownership.js +41 -8
  26. package/dist/install/transaction.d.ts.map +1 -1
  27. package/dist/install/transaction.js +42 -10
  28. package/dist/install/transaction.js.map +1 -1
  29. package/dist/install/ui.js +41 -8
  30. package/dist/installSession.js +1 -1
  31. package/dist/installation.js +41 -8
  32. package/dist/launcher.js +41 -8
  33. package/dist/preflight.js +201 -164
  34. package/dist/project/eligibility.js +41 -8
  35. package/dist/project/records.js +41 -8
  36. package/dist/project.d.ts +35 -1
  37. package/dist/project.d.ts.map +1 -1
  38. package/dist/project.js +294 -231
  39. package/dist/project.js.map +1 -1
  40. package/dist/router.d.ts +7 -0
  41. package/dist/router.d.ts.map +1 -1
  42. package/dist/router.js +340 -182
  43. package/dist/router.js.map +1 -1
  44. package/dist/runtime/bootstrap.d.ts +22 -1
  45. package/dist/runtime/bootstrap.d.ts.map +1 -1
  46. package/dist/runtime/bootstrap.js +61 -8
  47. package/dist/runtime/bootstrap.js.map +1 -1
  48. package/dist/runtime/releaseSource.js +41 -8
  49. package/dist/runtime/selfUpdate.js +41 -8
  50. package/dist/runtime/signers.js +789 -183
  51. package/dist/runtime/store.d.ts +1 -1
  52. package/dist/runtime/store.d.ts.map +1 -1
  53. package/dist/runtime/store.js +54 -5
  54. package/dist/runtime/store.js.map +1 -1
  55. package/dist/runtime/updateCheck.js +41 -8
  56. package/dist/sbom.json +21 -21
  57. package/dist/scanner/control.js +41 -8
  58. package/dist/scanner/data.js +1 -1
  59. package/dist/scanner/discover.d.ts.map +1 -1
  60. package/dist/scanner/discover.js +211 -171
  61. package/dist/scanner/discover.js.map +1 -1
  62. package/dist/scanner/enable.d.ts.map +1 -1
  63. package/dist/scanner/enable.js +440 -57
  64. package/dist/scanner/enable.js.map +1 -1
  65. package/dist/scanner/picker.d.ts.map +1 -1
  66. package/dist/scanner/picker.js +12 -4
  67. package/dist/scanner/picker.js.map +1 -1
  68. package/dist/scanner/service.js +41 -8
  69. package/dist/scanner/update.js +41 -8
  70. package/dist/scanner-release.json +24 -24
  71. package/dist/status.js +41 -8
  72. package/dist/vendor/local-setup.js +44 -11
  73. package/package.json +31 -31
@@ -729,13 +729,13 @@ var require_ignore = __commonJS({
729
729
  const rules = this._rules;
730
730
  const { length } = rules;
731
731
  const shortcut = this._basenameCount * 2 >= length;
732
- const basename2 = shortcut ? basenameOf(path) : path;
732
+ const basename3 = shortcut ? basenameOf(path) : path;
733
733
  for (let index = 0; index < length; index++) {
734
734
  const rule = rules[index];
735
735
  const { negative } = rule;
736
736
  const skip = unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored;
737
737
  if (!skip && rule[mode].test(
738
- shortcut && rule._basenameOnly ? basename2 : path
738
+ shortcut && rule._basenameOnly ? basename3 : path
739
739
  )) {
740
740
  ignored = !negative;
741
741
  unignored = negative;
@@ -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 repositoryFingerprint = 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
+ ...repositoryFingerprint ? { repositoryFingerprint } : {}
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;
@@ -982,18 +1092,265 @@ var init_repositoryFingerprint = __esm({
982
1092
  }
983
1093
  });
984
1094
 
985
- // packages/shared/dist/projectIdentityFile.js
986
- var init_projectIdentityFile = __esm({
987
- "packages/shared/dist/projectIdentityFile.js"() {
988
- "use strict";
989
- }
990
- });
991
-
992
1095
  // packages/shared/dist/repositoryRoot.js
1096
+ import { lstat as lstat2, readFile as readFile2, realpath } from "node:fs/promises";
1097
+ import { execFile as execFile2 } from "node:child_process";
1098
+ import { homedir } from "node:os";
1099
+ import { dirname as dirname3, join as join4, resolve as resolve2 } from "node:path";
1100
+ function gitEnvironment() {
1101
+ const env = {};
1102
+ for (const key of GIT_ENV_KEYS) {
1103
+ if (process.env[key] !== void 0)
1104
+ env[key] = process.env[key];
1105
+ }
1106
+ env.LC_ALL = "C";
1107
+ return env;
1108
+ }
1109
+ function runGit(cwd, args2) {
1110
+ return new Promise((resolvePromise, reject) => {
1111
+ execFile2("git", args2, { cwd, timeout: GIT_TIMEOUT_MS, encoding: "utf8", env: gitEnvironment() }, (error, stdout, stderr) => {
1112
+ if (error)
1113
+ reject(Object.assign(error, { stdout, stderr }));
1114
+ else
1115
+ resolvePromise({ stdout, stderr });
1116
+ });
1117
+ });
1118
+ }
1119
+ async function boundaryAt(path) {
1120
+ try {
1121
+ const stat = await lstat2(join4(path, ".git"));
1122
+ if (stat.isDirectory())
1123
+ return { path, kind: "directory" };
1124
+ if (stat.isFile())
1125
+ return { path, kind: "file" };
1126
+ } catch (error) {
1127
+ const code = error.code;
1128
+ if (code !== "ENOENT" && code !== "ENOTDIR")
1129
+ throw error;
1130
+ }
1131
+ return void 0;
1132
+ }
1133
+ async function confirmedBoundaryAt(path) {
1134
+ const boundary = await boundaryAt(path);
1135
+ if (!boundary)
1136
+ return void 0;
1137
+ try {
1138
+ const { stdout } = await runGit(path, ["rev-parse", "--git-dir"]);
1139
+ return stdout.trim() ? boundary : void 0;
1140
+ } catch {
1141
+ return void 0;
1142
+ }
1143
+ }
1144
+ async function boundariesBetween(cwd, root) {
1145
+ const boundaries = [];
1146
+ let directory = cwd;
1147
+ while (!samePath(directory, root)) {
1148
+ const boundary = await confirmedBoundaryAt(directory);
1149
+ if (boundary)
1150
+ boundaries.push(boundary);
1151
+ const parent = dirname3(directory);
1152
+ if (parent === directory)
1153
+ break;
1154
+ directory = parent;
1155
+ }
1156
+ return boundaries;
1157
+ }
1158
+ async function containingRepository(root) {
1159
+ let directory = dirname3(root);
1160
+ while (true) {
1161
+ const boundary = await confirmedBoundaryAt(directory);
1162
+ if (boundary)
1163
+ return boundary;
1164
+ const parent = dirname3(directory);
1165
+ if (parent === directory)
1166
+ return void 0;
1167
+ directory = parent;
1168
+ }
1169
+ }
1170
+ async function canonicalPath(path) {
1171
+ const absolute = resolve2(path);
1172
+ return realpath(absolute).catch(() => absolute);
1173
+ }
1174
+ function samePath(left, right) {
1175
+ return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
1176
+ }
1177
+ async function resolveRepositoryRoot(cwd) {
1178
+ const absoluteCwd = await canonicalPath(cwd);
1179
+ try {
1180
+ const { stdout } = await runGit(absoluteCwd, [
1181
+ "rev-parse",
1182
+ "--show-toplevel",
1183
+ "--git-dir",
1184
+ "--git-common-dir"
1185
+ ]);
1186
+ const [rootLine, gitDirLine, commonLine, ...extra] = stdout.trim().split(/\r?\n/);
1187
+ if (!rootLine || !gitDirLine || !commonLine || extra.length) {
1188
+ return { kind: "git_unavailable", detail: "git rev-parse returned an unexpected response" };
1189
+ }
1190
+ const fromGit = (line) => canonicalPath(resolve2(absoluteCwd, line));
1191
+ const root = await fromGit(rootLine);
1192
+ const gitDir = await fromGit(gitDirLine);
1193
+ const commonDir = await fromGit(commonLine);
1194
+ const isLinkedWorktree = !samePath(gitDir, commonDir);
1195
+ const nested = await boundariesBetween(absoluteCwd, root);
1196
+ if (!isLinkedWorktree && await containingRepository(root)) {
1197
+ const boundary = await boundaryAt(root);
1198
+ if (boundary)
1199
+ nested.push(boundary);
1200
+ }
1201
+ return {
1202
+ kind: "git",
1203
+ root,
1204
+ commonDir,
1205
+ isLinkedWorktree,
1206
+ nested
1207
+ };
1208
+ } catch (error) {
1209
+ const failure = error;
1210
+ if (failure.code === 128 && /not a git repository/i.test(failure.stderr ?? failure.message)) {
1211
+ return { kind: "plain", root: absoluteCwd };
1212
+ }
1213
+ return { kind: "git_unavailable", detail: failure.message };
1214
+ }
1215
+ }
1216
+ async function linkedWorktreeCommonDir(dir) {
1217
+ try {
1218
+ if (!(await lstat2(join4(dir, ".git"))).isFile())
1219
+ return void 0;
1220
+ const pointer = /^gitdir:\s*(.+?)\s*$/im.exec(await readFile2(join4(dir, ".git"), "utf8"))?.[1];
1221
+ if (!pointer)
1222
+ return void 0;
1223
+ const gitDir = resolve2(dir, pointer);
1224
+ const common = (await readFile2(join4(gitDir, "commondir"), "utf8")).trim();
1225
+ return common ? await canonicalPath(resolve2(gitDir, common)) : void 0;
1226
+ } catch {
1227
+ return void 0;
1228
+ }
1229
+ }
1230
+ async function mainCheckout(worktreeTop, commonDir) {
1231
+ try {
1232
+ const { stdout } = await runGit(worktreeTop, ["worktree", "list", "--porcelain"]);
1233
+ const first = stdout.split(/\r?\n\r?\n/)[0] ?? "";
1234
+ const path = /^worktree (.+)$/m.exec(first)?.[1];
1235
+ if (path) {
1236
+ const main = await canonicalPath(resolve2(worktreeTop, path));
1237
+ return /^bare$/m.test(first) ? dirname3(main) : main;
1238
+ }
1239
+ } catch {
1240
+ }
1241
+ return dirname3(commonDir);
1242
+ }
1243
+ async function readPlainIdentity(start2) {
1244
+ const home = await canonicalPath(homedir());
1245
+ let directory = start2;
1246
+ while (true) {
1247
+ const result = await readIdentityFile(directory, { configurationOnlyAbsent: true });
1248
+ if (result.kind !== "absent")
1249
+ return { root: directory, result };
1250
+ if (samePath(directory, home))
1251
+ break;
1252
+ const parent = dirname3(directory);
1253
+ if (parent === directory)
1254
+ break;
1255
+ directory = parent;
1256
+ }
1257
+ return { root: start2, result: { kind: "absent" } };
1258
+ }
1259
+ async function nearestIdentity(start2) {
1260
+ const home = await canonicalPath(homedir());
1261
+ let directory = start2;
1262
+ while (true) {
1263
+ const commonDir = await linkedWorktreeCommonDir(directory);
1264
+ if (commonDir)
1265
+ return { worktreeTop: directory, commonDir };
1266
+ const result = await readIdentityFile(directory, { configurationOnlyAbsent: true });
1267
+ if (result.kind !== "absent")
1268
+ return { root: directory, result };
1269
+ if (samePath(directory, home))
1270
+ return void 0;
1271
+ const parent = dirname3(directory);
1272
+ if (parent === directory)
1273
+ return void 0;
1274
+ directory = parent;
1275
+ }
1276
+ }
1277
+ async function resolveNearestProjectIdentity(cwd) {
1278
+ const start2 = await canonicalPath(cwd);
1279
+ const resolved = await resolveRepositoryRoot(start2);
1280
+ const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: start2 } : resolved;
1281
+ const nested = repository.kind === "git" ? repository.nested : [];
1282
+ let found = await nearestIdentity(start2);
1283
+ if (found && "worktreeTop" in found) {
1284
+ found = await readPlainIdentity(await mainCheckout(found.worktreeTop, found.commonDir));
1285
+ }
1286
+ if (found) {
1287
+ return shapedIdentity(found, await projectFolderRepository(found.root, repository), nested);
1288
+ }
1289
+ return { ...withBase(repository, repository.root, nested), kind: "absent" };
1290
+ }
1291
+ async function resolveNamedProjectIdentity(cwd, options) {
1292
+ const start2 = await canonicalPath(cwd);
1293
+ const resolved = await resolveRepositoryRoot(start2);
1294
+ const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: start2 } : resolved;
1295
+ const commonDir = await linkedWorktreeCommonDir(start2);
1296
+ const root = commonDir ? await mainCheckout(start2, commonDir) : start2;
1297
+ return shapedIdentity({ root, result: await readIdentityFile(root, options) }, await projectFolderRepository(root, repository), repository.kind === "git" ? repository.nested : []);
1298
+ }
1299
+ function shapedIdentity(found, repository, nested) {
1300
+ const base = withBase(repository, found.root, nested);
1301
+ if (found.result.kind === "ok")
1302
+ return { ...base, ...found.result };
1303
+ if (found.result.kind === "unknown_version")
1304
+ return { ...base, ...found.result, path: found.root };
1305
+ if (found.result.kind === "malformed")
1306
+ return { ...base, ...found.result, path: found.root };
1307
+ return { ...base, kind: "absent" };
1308
+ }
1309
+ async function projectFolderRepository(projectRoot, known) {
1310
+ if (known.kind === "git" && samePath(known.root, projectRoot))
1311
+ return known;
1312
+ const repository = await resolveRepositoryRoot(projectRoot);
1313
+ if (repository.kind === "git" && samePath(repository.root, projectRoot))
1314
+ return repository;
1315
+ return { kind: "plain", root: projectRoot };
1316
+ }
1317
+ function withBase(repository, root, nested) {
1318
+ return { root, repository, nested };
1319
+ }
1320
+ async function resolveProjectIdentity(cwd, options = {}) {
1321
+ if (options.selectedRoot || options.namedRoot) {
1322
+ return resolveNamedProjectIdentity(cwd, { selectedRoot: options.selectedRoot });
1323
+ }
1324
+ return resolveNearestProjectIdentity(cwd);
1325
+ }
1326
+ var GIT_TIMEOUT_MS, GIT_ENV_KEYS;
993
1327
  var init_repositoryRoot = __esm({
994
1328
  "packages/shared/dist/repositoryRoot.js"() {
995
1329
  "use strict";
996
1330
  init_projectIdentityFile();
1331
+ GIT_TIMEOUT_MS = 2e3;
1332
+ GIT_ENV_KEYS = [
1333
+ "PATH",
1334
+ "HOME",
1335
+ "LANG",
1336
+ "LC_ALL",
1337
+ "SYSTEMROOT",
1338
+ "TEMP",
1339
+ "TMP",
1340
+ "USERPROFILE"
1341
+ ];
1342
+ }
1343
+ });
1344
+
1345
+ // packages/shared/dist/hookTrace.js
1346
+ var HOOK_TRACE_MAX_BYTES;
1347
+ var init_hookTrace = __esm({
1348
+ "packages/shared/dist/hookTrace.js"() {
1349
+ "use strict";
1350
+ init_protectedPaths();
1351
+ init_runtimeSigners();
1352
+ init_secretPatterns();
1353
+ HOOK_TRACE_MAX_BYTES = 2 * 1024 * 1024;
997
1354
  }
998
1355
  });
999
1356
 
@@ -1068,10 +1425,12 @@ var init_hookRuntime = __esm({
1068
1425
  init_runtimeSigners();
1069
1426
  init_hookTimeouts();
1070
1427
  init_repositoryRoot();
1428
+ init_hookTrace();
1071
1429
  init_runtimeReader();
1072
1430
  init_runtimeSigners();
1073
1431
  init_projectSetupHandoff();
1074
1432
  init_hookConversation();
1433
+ init_hookTrace();
1075
1434
  }
1076
1435
  });
1077
1436
 
@@ -1567,8 +1926,8 @@ var require_graceful_fs = __commonJS({
1567
1926
  fs4.createReadStream = createReadStream;
1568
1927
  fs4.createWriteStream = createWriteStream;
1569
1928
  var fs$readFile = fs4.readFile;
1570
- fs4.readFile = readFile3;
1571
- function readFile3(path, options, cb) {
1929
+ fs4.readFile = readFile5;
1930
+ function readFile5(path, options, cb) {
1572
1931
  if (typeof options === "function")
1573
1932
  cb = options, options = null;
1574
1933
  return go$readFile(path, options, cb);
@@ -2574,12 +2933,12 @@ var require_adapter = __commonJS({
2574
2933
  return newFs;
2575
2934
  }
2576
2935
  function toPromise(method) {
2577
- return (...args2) => new Promise((resolve2, reject) => {
2936
+ return (...args2) => new Promise((resolve3, reject) => {
2578
2937
  args2.push((err2, result) => {
2579
2938
  if (err2) {
2580
2939
  reject(err2);
2581
2940
  } else {
2582
- resolve2(result);
2941
+ resolve3(result);
2583
2942
  }
2584
2943
  });
2585
2944
  method(...args2);
@@ -2654,12 +3013,12 @@ var require_proper_lockfile = __commonJS({
2654
3013
 
2655
3014
  // packages/cli/src/scanner/enable.ts
2656
3015
  import { revokeInstallComponent } from "../install/transaction.js";
2657
- import { mkdir as mkdir2, readFile as readFile2, realpath } from "node:fs/promises";
2658
- import { join as join5 } from "node:path";
3016
+ import { mkdir as mkdir2, readFile as readFile4, realpath as realpath2 } from "node:fs/promises";
3017
+ import { basename as basename2, join as join7 } from "node:path";
2659
3018
  import { isDeepStrictEqual } from "node:util";
2660
3019
 
2661
3020
  // packages/shared/dist/instructions.js
2662
- var INSTRUCTIONS_CONTENT = `Mnemonik provides persistent project memory: decisions, rationale, tasks, and policies across sessions. If no block begins "PROJECT_CONTEXT schemaVersion=", session_bootstrap({ cwd }) loads project context when cwd is the real absolute path of the project root; a placeholder or relative path fails. With that block, context is loaded and no session_bootstrap call is needed. Code and docs show current artifacts, git shows changes, and memory carries the why; memory_search recalls rationale or intent, then Grep or Read verifies current source.
3021
+ var INSTRUCTIONS_CONTENT = `Mnemonik provides persistent project memory: decisions, rationale, tasks, and policies across sessions. If no block begins "PROJECT_CONTEXT schemaVersion=", session_bootstrap({}) loads project context; installed hooks supply the project. With that block, context is loaded and no session_bootstrap call is needed. Code and docs show current artifacts, git shows changes, and memory carries the why; memory_search recalls rationale or intent, then Grep or Read verifies current source.
2663
3022
 
2664
3023
  What I learn about you belongs in Companion; what I learn about this project belongs here.
2665
3024
 
@@ -2696,6 +3055,9 @@ var MCP_INSTRUCTIONS = getMcpInstructions();
2696
3055
 
2697
3056
  // packages/shared/dist/codeScanner.js
2698
3057
  var import_ignore = __toESM(require_ignore(), 1);
3058
+ init_secretPatterns();
3059
+ init_protectedPaths();
3060
+ init_projectIdentityFile();
2699
3061
 
2700
3062
  // node_modules/web-tree-sitter/web-tree-sitter.js
2701
3063
  var __defProp2 = Object.defineProperty;
@@ -4326,13 +4688,13 @@ async function Module2(moduleArg = {}) {
4326
4688
  }
4327
4689
  readAsync = /* @__PURE__ */ __name(async (url) => {
4328
4690
  if (isFileURI(url)) {
4329
- return new Promise((resolve2, reject) => {
4691
+ return new Promise((resolve3, reject) => {
4330
4692
  var xhr = new XMLHttpRequest();
4331
4693
  xhr.open("GET", url, true);
4332
4694
  xhr.responseType = "arraybuffer";
4333
4695
  xhr.onload = () => {
4334
4696
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
4335
- resolve2(xhr.response);
4697
+ resolve3(xhr.response);
4336
4698
  return;
4337
4699
  }
4338
4700
  reject(xhr.status);
@@ -4528,9 +4890,9 @@ async function Module2(moduleArg = {}) {
4528
4890
  __name(receiveInstantiationResult, "receiveInstantiationResult");
4529
4891
  var info22 = getWasmImports();
4530
4892
  if (Module["instantiateWasm"]) {
4531
- return new Promise((resolve2, reject) => {
4893
+ return new Promise((resolve3, reject) => {
4532
4894
  Module["instantiateWasm"](info22, (mod, inst) => {
4533
- resolve2(receiveInstance(mod, inst));
4895
+ resolve3(receiveInstance(mod, inst));
4534
4896
  });
4535
4897
  });
4536
4898
  }
@@ -5863,8 +6225,8 @@ async function Module2(moduleArg = {}) {
5863
6225
  if (runtimeInitialized) {
5864
6226
  moduleRtn = Module;
5865
6227
  } else {
5866
- moduleRtn = new Promise((resolve2, reject) => {
5867
- readyPromiseResolve = resolve2;
6228
+ moduleRtn = new Promise((resolve3, reject) => {
6229
+ readyPromiseResolve = resolve3;
5868
6230
  readyPromiseReject = reject;
5869
6231
  });
5870
6232
  }
@@ -6741,9 +7103,9 @@ var Query = class {
6741
7103
  };
6742
7104
 
6743
7105
  // packages/shared/dist/ast/grammars.js
6744
- import { dirname, extname, join } from "node:path";
7106
+ import { dirname, extname, join as join2 } from "node:path";
6745
7107
  import { fileURLToPath } from "node:url";
6746
- var WASM_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
7108
+ var WASM_DIR = join2(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
6747
7109
 
6748
7110
  // packages/shared/dist/ast/astChunker.js
6749
7111
  var MAX_AST_PARSE_BYTES = 2 * 1024 * 1024;
@@ -6921,6 +7283,7 @@ var BUILT_IN_IGNORE_DIR_SET = new Set(BUILT_IN_IGNORE_DIRS);
6921
7283
  var import_ignore2 = __toESM(require_ignore(), 1);
6922
7284
 
6923
7285
  // packages/shared/dist/index.js
7286
+ init_secretPatterns();
6924
7287
  init_hookTimeouts();
6925
7288
 
6926
7289
  // packages/shared/dist/jitDeliveryAck.js
@@ -6936,6 +7299,7 @@ init_settingsIo();
6936
7299
  init_repositoryFingerprint();
6937
7300
  init_projectIdentityFile();
6938
7301
  init_repositoryRoot();
7302
+ init_protectedPaths();
6939
7303
 
6940
7304
  // packages/shared/dist/readiness.js
6941
7305
  var READINESS_SCHEMA_VERSION = 1;
@@ -7041,9 +7405,9 @@ init_hookRuntime();
7041
7405
  import { createHash, randomUUID } from "node:crypto";
7042
7406
  import { execFile as nodeExecFile } from "node:child_process";
7043
7407
  import fs2 from "node:fs";
7044
- import { open, rename, readFile, mkdir, lstat, chmod, writeFile, unlink, rmdir } from "node:fs/promises";
7045
- import { homedir } from "node:os";
7046
- import { dirname as dirname3, join as join3, win32 as win322, posix } from "node:path";
7408
+ import { open, rename, readFile as readFile3, mkdir, lstat as lstat3, chmod, writeFile, unlink, rmdir } from "node:fs/promises";
7409
+ import { homedir as homedir2 } from "node:os";
7410
+ import { dirname as dirname4, join as join5, win32 as win322, posix } from "node:path";
7047
7411
  import { setTimeout as delay } from "node:timers/promises";
7048
7412
  var lockfileKey = /* @__PURE__ */ Symbol.for("mnemonik.proper-lockfile");
7049
7413
  function sharedLockfile() {
@@ -7051,7 +7415,7 @@ function sharedLockfile() {
7051
7415
  return shared[lockfileKey] ??= Promise.resolve().then(() => __toESM(require_proper_lockfile(), 1)).then((module2) => module2.default);
7052
7416
  }
7053
7417
  var codeIs = (error, code) => error.code === code;
7054
- function stateDirectory(platform = process.platform, env = process.env, home = homedir()) {
7418
+ function stateDirectory(platform = process.platform, env = process.env, home = homedir2()) {
7055
7419
  if (env.MNEMONIK_STATE_DIR)
7056
7420
  return env.MNEMONIK_STATE_DIR;
7057
7421
  if (platform === "win32")
@@ -7062,9 +7426,9 @@ function stateDirectory(platform = process.platform, env = process.env, home = h
7062
7426
  }
7063
7427
  async function readBytes(path) {
7064
7428
  try {
7065
- if (!(await lstat(path)).isFile())
7429
+ if (!(await lstat3(path)).isFile())
7066
7430
  throw new Error("setup_requires_regular_file");
7067
- return await readFile(path);
7431
+ return await readFile3(path);
7068
7432
  } catch (error) {
7069
7433
  if (codeIs(error, "ENOENT"))
7070
7434
  return null;
@@ -7085,9 +7449,9 @@ var windowsCurrentAccount = windowsCurrentAccountSync;
7085
7449
  async function windowsCurrentUserAcl(path, directory = false, options = {}, created = false) {
7086
7450
  const username = options.username ?? `*${windowsCurrentAccount().sid}`;
7087
7451
  const grant = `${username}:${directory ? "(OI)(CI)F" : "F"}`;
7088
- const execFile2 = options.execFile ?? nodeExecFile;
7089
- await new Promise((resolve2, reject) => {
7090
- execFile2("icacls.exe", [
7452
+ const execFile3 = options.execFile ?? nodeExecFile;
7453
+ await new Promise((resolve3, reject) => {
7454
+ execFile3("icacls.exe", [
7091
7455
  path,
7092
7456
  "/inheritance:r",
7093
7457
  "/grant:r",
@@ -7097,7 +7461,7 @@ async function windowsCurrentUserAcl(path, directory = false, options = {}, crea
7097
7461
  if (error)
7098
7462
  reject(error);
7099
7463
  else
7100
- resolve2();
7464
+ resolve3();
7101
7465
  });
7102
7466
  });
7103
7467
  }
@@ -7126,14 +7490,14 @@ async function atomicWrite(path, bytes, fault, assertOwned) {
7126
7490
  }
7127
7491
  await assertOwned?.();
7128
7492
  await rename(temp, path);
7129
- await syncDirectory(dirname3(path));
7493
+ await syncDirectory(dirname4(path));
7130
7494
  return permissionStatus;
7131
7495
  }
7132
7496
  async function withLock(path, waitMs, work) {
7133
7497
  const lockfile = await sharedLockfile();
7134
- await mkdir(dirname3(path), { recursive: true, mode: 448 });
7498
+ await mkdir(dirname4(path), { recursive: true, mode: 448 });
7135
7499
  const generation = randomUUID();
7136
- const owner = join3(`${path}.lock`, "owner");
7500
+ const owner = join5(`${path}.lock`, "owner");
7137
7501
  let compromised = false;
7138
7502
  let acquired = false;
7139
7503
  const assertOwned = async () => {
@@ -7148,14 +7512,14 @@ async function withLock(path, waitMs, work) {
7148
7512
  void mkdir(dir).then(() => writeFile(owner, generation, { mode: 384, flag: "wx" })).then(() => callback(), callback);
7149
7513
  },
7150
7514
  rmdir: (dir, callback) => {
7151
- void unlink(join3(dir, "owner")).catch((error) => {
7515
+ void unlink(join5(dir, "owner")).catch((error) => {
7152
7516
  if (!codeIs(error, "ENOENT"))
7153
7517
  throw error;
7154
7518
  }).then(() => rmdir(dir)).then(() => callback(), callback);
7155
7519
  },
7156
7520
  rmdirSync: (dir) => {
7157
7521
  try {
7158
- fs2.unlinkSync(join3(dir, "owner"));
7522
+ fs2.unlinkSync(join5(dir, "owner"));
7159
7523
  } catch (error) {
7160
7524
  if (!codeIs(error, "ENOENT"))
7161
7525
  throw error;
@@ -7201,15 +7565,15 @@ async function withLock(path, waitMs, work) {
7201
7565
  import { spawn as nodeSpawn } from "node:child_process";
7202
7566
  import { realpathSync } from "node:fs";
7203
7567
  import { stat as nodeStat, utimes } from "node:fs/promises";
7204
- import { homedir as homedir2 } from "node:os";
7205
- import { join as join4 } from "node:path";
7568
+ import { homedir as homedir3 } from "node:os";
7569
+ import { join as join6 } from "node:path";
7206
7570
  import { fileURLToPath as fileURLToPath2 } from "node:url";
7207
7571
  var DAY_MS = 864e5;
7208
- var statePath = (stateDir) => join4(stateDir, "automatic-update.json");
7572
+ var statePath = (stateDir) => join6(stateDir, "automatic-update.json");
7209
7573
  function cliLauncherPath(options = {}) {
7210
7574
  const platform = options.platform ?? process.platform;
7211
- const home = options.home ?? homedir2();
7212
- return platform === "win32" ? join4(options.env?.LOCALAPPDATA || join4(home, "AppData", "Local"), "Mnemonik", "bin", "mnemonik.cmd") : join4(home, ".local", "bin", "mnemonik");
7575
+ const home = options.home ?? homedir3();
7576
+ return platform === "win32" ? join6(options.env?.LOCALAPPDATA || join6(home, "AppData", "Local"), "Mnemonik", "bin", "mnemonik.cmd") : join6(home, ".local", "bin", "mnemonik");
7213
7577
  }
7214
7578
  async function readState(path) {
7215
7579
  const bytes = await readBytes(path);
@@ -7317,6 +7681,8 @@ import {
7317
7681
  connectedProjectsMessage,
7318
7682
  createRealProjectRuntime,
7319
7683
  ensureProjectRoot,
7684
+ insideProjectLine,
7685
+ projectFolderFor,
7320
7686
  projectLimitMessage
7321
7687
  } from "../project.js";
7322
7688
  import { consentDraft, runScannerBoundaryPicker } from "./picker.js";
@@ -7324,10 +7690,10 @@ var scannerStateBytes = (state) => Buffer.from(`${JSON.stringify(state, null, 2)
7324
7690
  `);
7325
7691
  var SCANNER_APPROVAL_WAIT = "Waiting for approval in your browser, up to 10 minutes.";
7326
7692
  async function updateScannerRoots(options) {
7327
- await mkdir2(join5(options.stateDir, "scanner"), { recursive: true, mode: 448 });
7328
- return withLock(join5(options.stateDir, "scanner/enable"), 5e3, async () => {
7329
- const path = join5(options.stateDir, "scanner/state.json");
7330
- const state = JSON.parse(await readFile2(path, "utf8"));
7693
+ await mkdir2(join7(options.stateDir, "scanner"), { recursive: true, mode: 448 });
7694
+ return withLock(join7(options.stateDir, "scanner/enable"), 5e3, async () => {
7695
+ const path = join7(options.stateDir, "scanner/state.json");
7696
+ const state = JSON.parse(await readFile4(path, "utf8"));
7331
7697
  const response = await (options.fetch ?? fetch)(
7332
7698
  `${apiOrigin()}/api/v1/scanner-consent/current`,
7333
7699
  {
@@ -7392,7 +7758,10 @@ async function enableScanner(options) {
7392
7758
  const executor = await prepared.projectExecutor();
7393
7759
  const connected = [];
7394
7760
  let limit;
7395
- for (const root of [...prepared.roots]) {
7761
+ const projectFolders = /* @__PURE__ */ new Set();
7762
+ for (const folder of prepared.roots)
7763
+ projectFolders.add(await projectFolderFor(folder, executor));
7764
+ for (const root of projectFolders) {
7396
7765
  const result = await ensureProjectRoot(root, executor);
7397
7766
  if (result.status === "done") connected.push(root);
7398
7767
  else {
@@ -7415,13 +7784,13 @@ async function enableScanner(options) {
7415
7784
  });
7416
7785
  }
7417
7786
  async function prepareScanner(options, work) {
7418
- await mkdir2(join5(options.stateDir, "scanner"), { recursive: true, mode: 448 });
7419
- return withLock(join5(options.stateDir, "scanner/enable"), 5e3, async () => {
7420
- const path = join5(options.stateDir, "scanner/state.json");
7787
+ await mkdir2(join7(options.stateDir, "scanner"), { recursive: true, mode: 448 });
7788
+ return withLock(join7(options.stateDir, "scanner/enable"), 5e3, async () => {
7789
+ const path = join7(options.stateDir, "scanner/state.json");
7421
7790
  if (await resumeAbandonedPause(options))
7422
7791
  if (options.nonInteractive) options.output.error(ABANDONED_PAUSE_RESUMED);
7423
7792
  else options.output.line(ABANDONED_PAUSE_RESUMED);
7424
- const saved = JSON.parse(await readFile2(path, "utf8").catch(() => "null"));
7793
+ const saved = JSON.parse(await readFile4(path, "utf8").catch(() => "null"));
7425
7794
  const credentials = options.credentials ?? createCliCredentials({ stateDir: options.stateDir });
7426
7795
  const authorize = options.authorize ?? (async (selection, installation) => {
7427
7796
  const auth = createCliAuth({
@@ -7500,8 +7869,22 @@ async function prepareScanner(options, work) {
7500
7869
  if ("status" in picked) throw new Error("consent_declined");
7501
7870
  if (!picked.roots.length && !picked.candidates?.length)
7502
7871
  throw new Error("scan_roots_required");
7503
- picked.roots = await Promise.all(picked.roots.map((root) => realpath(root)));
7504
- picked.exclusions = await Promise.all(picked.exclusions.map((root) => realpath(root)));
7872
+ picked.roots = await Promise.all(picked.roots.map((root) => realpath2(root)));
7873
+ if (options.roots) {
7874
+ const resolver = options.projectExecutor ?? { resolveProjectIdentity };
7875
+ const folders = [];
7876
+ for (const named of picked.roots) {
7877
+ const folder = await projectFolderFor(named, resolver);
7878
+ if (folder !== named) {
7879
+ const line = insideProjectLine(basename2(named), folder);
7880
+ if (options.nonInteractive) options.output.error(line);
7881
+ else options.output.line(line);
7882
+ }
7883
+ if (!folders.includes(folder)) folders.push(folder);
7884
+ }
7885
+ picked.roots = folders;
7886
+ }
7887
+ picked.exclusions = await Promise.all(picked.exclusions.map((root) => realpath2(root)));
7505
7888
  for (const root of picked.roots) {
7506
7889
  const decision = await evaluateRoot(
7507
7890
  { kind: "absent", root, repository: await repositoryAt(root), nested: [] },
@@ -7757,7 +8140,7 @@ async function restoreScannerInstall(journal, options) {
7757
8140
  if (!before?.installed) await service.restore("scanner", record.before);
7758
8141
  }
7759
8142
  if (record?.started)
7760
- await observeScannerState(journal, join5(options.stateDir, "scanner/state.json"));
8143
+ await observeScannerState(journal, join7(options.stateDir, "scanner/state.json"));
7761
8144
  for (const target of [...journal.data.targets].reverse().filter((t) => t.group?.startsWith("scanner:")))
7762
8145
  await journal.restore(target);
7763
8146
  if (record?.started && before?.installed) await service.restore("scanner", record.before);