@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
@@ -876,7 +876,7 @@ import { humanReason, humanReport } from "./humanReason.js";
876
876
  import { devReadiness } from "./runtime/releaseSource.js";
877
877
 
878
878
  // packages/shared/dist/instructions.js
879
- 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.
879
+ 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.
880
880
 
881
881
  What I learn about you belongs in Companion; what I learn about this project belongs here.
882
882
 
@@ -885,6 +885,27 @@ 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
+ var init_projectIdentityFile = __esm({
904
+ "packages/shared/dist/projectIdentityFile.js"() {
905
+ "use strict";
906
+ }
907
+ });
908
+
888
909
  // packages/shared/dist/hookTimeouts.js
889
910
  var init_hookTimeouts = __esm({
890
911
  "packages/shared/dist/hookTimeouts.js"() {
@@ -982,13 +1003,6 @@ var init_repositoryFingerprint = __esm({
982
1003
  }
983
1004
  });
984
1005
 
985
- // packages/shared/dist/projectIdentityFile.js
986
- var init_projectIdentityFile = __esm({
987
- "packages/shared/dist/projectIdentityFile.js"() {
988
- "use strict";
989
- }
990
- });
991
-
992
1006
  // packages/shared/dist/repositoryRoot.js
993
1007
  var init_repositoryRoot = __esm({
994
1008
  "packages/shared/dist/repositoryRoot.js"() {
@@ -997,6 +1011,18 @@ var init_repositoryRoot = __esm({
997
1011
  }
998
1012
  });
999
1013
 
1014
+ // packages/shared/dist/hookTrace.js
1015
+ var HOOK_TRACE_MAX_BYTES;
1016
+ var init_hookTrace = __esm({
1017
+ "packages/shared/dist/hookTrace.js"() {
1018
+ "use strict";
1019
+ init_protectedPaths();
1020
+ init_runtimeSigners();
1021
+ init_secretPatterns();
1022
+ HOOK_TRACE_MAX_BYTES = 2 * 1024 * 1024;
1023
+ }
1024
+ });
1025
+
1000
1026
  // packages/shared/dist/runtimeReader.js
1001
1027
  var RuntimeError;
1002
1028
  var init_runtimeReader = __esm({
@@ -1068,10 +1094,12 @@ var init_hookRuntime = __esm({
1068
1094
  init_runtimeSigners();
1069
1095
  init_hookTimeouts();
1070
1096
  init_repositoryRoot();
1097
+ init_hookTrace();
1071
1098
  init_runtimeReader();
1072
1099
  init_runtimeSigners();
1073
1100
  init_projectSetupHandoff();
1074
1101
  init_hookConversation();
1102
+ init_hookTrace();
1075
1103
  }
1076
1104
  });
1077
1105
 
@@ -2657,7 +2685,7 @@ import { mkdir as mkdir2 } from "node:fs/promises";
2657
2685
  import { join as join5 } from "node:path";
2658
2686
 
2659
2687
  // packages/shared/dist/instructions.js
2660
- 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.
2688
+ 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.
2661
2689
 
2662
2690
  What I learn about you belongs in Companion; what I learn about this project belongs here.
2663
2691
 
@@ -2694,6 +2722,9 @@ var MCP_INSTRUCTIONS = getMcpInstructions();
2694
2722
 
2695
2723
  // packages/shared/dist/codeScanner.js
2696
2724
  var import_ignore = __toESM(require_ignore(), 1);
2725
+ init_secretPatterns();
2726
+ init_protectedPaths();
2727
+ init_projectIdentityFile();
2697
2728
 
2698
2729
  // node_modules/web-tree-sitter/web-tree-sitter.js
2699
2730
  var __defProp2 = Object.defineProperty;
@@ -6919,6 +6950,7 @@ var BUILT_IN_IGNORE_DIR_SET = new Set(BUILT_IN_IGNORE_DIRS);
6919
6950
  var import_ignore2 = __toESM(require_ignore(), 1);
6920
6951
 
6921
6952
  // packages/shared/dist/index.js
6953
+ init_secretPatterns();
6922
6954
  init_hookTimeouts();
6923
6955
 
6924
6956
  // packages/shared/dist/jitDeliveryAck.js
@@ -6934,6 +6966,7 @@ init_settingsIo();
6934
6966
  init_repositoryFingerprint();
6935
6967
  init_projectIdentityFile();
6936
6968
  init_repositoryRoot();
6969
+ init_protectedPaths();
6937
6970
 
6938
6971
  // packages/local-setup/dist/storage.js
6939
6972
  init_hookRuntime();
package/dist/launcher.js CHANGED
@@ -885,6 +885,27 @@ 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
+ var init_projectIdentityFile = __esm({
904
+ "packages/shared/dist/projectIdentityFile.js"() {
905
+ "use strict";
906
+ }
907
+ });
908
+
888
909
  // packages/shared/dist/hookTimeouts.js
889
910
  var init_hookTimeouts = __esm({
890
911
  "packages/shared/dist/hookTimeouts.js"() {
@@ -982,13 +1003,6 @@ var init_repositoryFingerprint = __esm({
982
1003
  }
983
1004
  });
984
1005
 
985
- // packages/shared/dist/projectIdentityFile.js
986
- var init_projectIdentityFile = __esm({
987
- "packages/shared/dist/projectIdentityFile.js"() {
988
- "use strict";
989
- }
990
- });
991
-
992
1006
  // packages/shared/dist/repositoryRoot.js
993
1007
  var init_repositoryRoot = __esm({
994
1008
  "packages/shared/dist/repositoryRoot.js"() {
@@ -997,6 +1011,18 @@ var init_repositoryRoot = __esm({
997
1011
  }
998
1012
  });
999
1013
 
1014
+ // packages/shared/dist/hookTrace.js
1015
+ var HOOK_TRACE_MAX_BYTES;
1016
+ var init_hookTrace = __esm({
1017
+ "packages/shared/dist/hookTrace.js"() {
1018
+ "use strict";
1019
+ init_protectedPaths();
1020
+ init_runtimeSigners();
1021
+ init_secretPatterns();
1022
+ HOOK_TRACE_MAX_BYTES = 2 * 1024 * 1024;
1023
+ }
1024
+ });
1025
+
1000
1026
  // packages/shared/dist/runtimeReader.js
1001
1027
  var RuntimeError;
1002
1028
  var init_runtimeReader = __esm({
@@ -1068,10 +1094,12 @@ var init_hookRuntime = __esm({
1068
1094
  init_runtimeSigners();
1069
1095
  init_hookTimeouts();
1070
1096
  init_repositoryRoot();
1097
+ init_hookTrace();
1071
1098
  init_runtimeReader();
1072
1099
  init_runtimeSigners();
1073
1100
  init_projectSetupHandoff();
1074
1101
  init_hookConversation();
1102
+ init_hookTrace();
1075
1103
  }
1076
1104
  });
1077
1105
 
@@ -2659,7 +2687,7 @@ import { homedir as homedir3 } from "node:os";
2659
2687
  import { basename as basename2, isAbsolute, join as join5, resolve as resolve2 } from "node:path";
2660
2688
 
2661
2689
  // 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.
2690
+ 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
2691
 
2664
2692
  What I learn about you belongs in Companion; what I learn about this project belongs here.
2665
2693
 
@@ -2696,6 +2724,9 @@ var MCP_INSTRUCTIONS = getMcpInstructions();
2696
2724
 
2697
2725
  // packages/shared/dist/codeScanner.js
2698
2726
  var import_ignore = __toESM(require_ignore(), 1);
2727
+ init_secretPatterns();
2728
+ init_protectedPaths();
2729
+ init_projectIdentityFile();
2699
2730
 
2700
2731
  // node_modules/web-tree-sitter/web-tree-sitter.js
2701
2732
  var __defProp2 = Object.defineProperty;
@@ -6921,6 +6952,7 @@ var BUILT_IN_IGNORE_DIR_SET = new Set(BUILT_IN_IGNORE_DIRS);
6921
6952
  var import_ignore2 = __toESM(require_ignore(), 1);
6922
6953
 
6923
6954
  // packages/shared/dist/index.js
6955
+ init_secretPatterns();
6924
6956
  init_hookTimeouts();
6925
6957
 
6926
6958
  // packages/shared/dist/jitDeliveryAck.js
@@ -6936,6 +6968,7 @@ init_settingsIo();
6936
6968
  init_repositoryFingerprint();
6937
6969
  init_projectIdentityFile();
6938
6970
  init_repositoryRoot();
6971
+ init_protectedPaths();
6939
6972
 
6940
6973
  // packages/local-setup/dist/storage.js
6941
6974
  init_hookRuntime();
package/dist/preflight.js CHANGED
@@ -877,7 +877,7 @@ import { homedir as homedir2 } from "node:os";
877
877
  import { join as join4 } from "node:path";
878
878
 
879
879
  // packages/shared/dist/instructions.js
880
- 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.
880
+ 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.
881
881
 
882
882
  What I learn about you belongs in Companion; what I learn about this project belongs here.
883
883
 
@@ -915,6 +915,96 @@ var MCP_INSTRUCTIONS = getMcpInstructions();
915
915
  // packages/shared/dist/codeScanner.js
916
916
  var import_ignore = __toESM(require_ignore(), 1);
917
917
 
918
+ // packages/shared/dist/projectIdentityFile.js
919
+ import { lstat, readFile } from "node:fs/promises";
920
+ import { join } from "node:path";
921
+ var 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}$/;
922
+ var isCanonicalUuid = (value) => typeof value === "string" && CANONICAL_UUID.test(value);
923
+ var IDENTITY_KEYS = /* @__PURE__ */ new Set([
924
+ "schemaVersion",
925
+ "projectId",
926
+ "projectName",
927
+ "repositoryFingerprint"
928
+ ]);
929
+ var FINGERPRINT_KEYS = /* @__PURE__ */ new Set(["algorithmVersion", "hash"]);
930
+ function parseIdentityFile(text) {
931
+ let value;
932
+ try {
933
+ value = JSON.parse(text);
934
+ } catch (error) {
935
+ return { kind: "malformed", detail: `unparseable JSON: ${error.message}` };
936
+ }
937
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
938
+ return { kind: "malformed", detail: "identity file must contain a JSON object" };
939
+ }
940
+ const record = value;
941
+ if (record.schemaVersion !== 1) {
942
+ return { kind: "unknown_version", version: record.schemaVersion };
943
+ }
944
+ const unknownKey = Object.keys(record).find((key) => !IDENTITY_KEYS.has(key));
945
+ if (unknownKey)
946
+ return { kind: "malformed", detail: `unknown key "${unknownKey}"` };
947
+ if (!isCanonicalUuid(record.projectId)) {
948
+ return { kind: "malformed", detail: '"projectId" must be a canonical RFC 4122 UUID string' };
949
+ }
950
+ if ("projectName" in record && typeof record.projectName !== "string") {
951
+ return { kind: "malformed", detail: '"projectName" must be a string when present' };
952
+ }
953
+ if ("repositoryFingerprint" in record && (!record.repositoryFingerprint || typeof record.repositoryFingerprint !== "object" || Array.isArray(record.repositoryFingerprint))) {
954
+ return { kind: "malformed", detail: '"repositoryFingerprint" must be an object when present' };
955
+ }
956
+ const fingerprint = record.repositoryFingerprint;
957
+ const unknownFingerprintKey = fingerprint ? Object.keys(fingerprint).find((key) => !FINGERPRINT_KEYS.has(key)) : void 0;
958
+ if (unknownFingerprintKey) {
959
+ return {
960
+ kind: "malformed",
961
+ detail: `unknown repositoryFingerprint key "${unknownFingerprintKey}"`
962
+ };
963
+ }
964
+ if (fingerprint && (fingerprint.algorithmVersion !== 1 || typeof fingerprint.hash !== "string")) {
965
+ return {
966
+ kind: "malformed",
967
+ detail: '"repositoryFingerprint" must contain algorithmVersion 1 and a string hash'
968
+ };
969
+ }
970
+ const repositoryFingerprint = fingerprint ? { algorithmVersion: 1, hash: fingerprint.hash } : void 0;
971
+ return {
972
+ kind: "ok",
973
+ identity: {
974
+ schemaVersion: 1,
975
+ projectId: record.projectId,
976
+ ...record.projectName === void 0 ? {} : { projectName: record.projectName },
977
+ ...repositoryFingerprint ? { repositoryFingerprint } : {}
978
+ }
979
+ };
980
+ }
981
+ function isConfigurationOnly(text) {
982
+ try {
983
+ const value = JSON.parse(text);
984
+ return !!value && typeof value === "object" && !Array.isArray(value) && !("projectId" in value) && (!("schemaVersion" in value) || value.schemaVersion === 1);
985
+ } catch {
986
+ return false;
987
+ }
988
+ }
989
+ async function readIdentityFile(dir, options = {}) {
990
+ const path = join(dir, ".mnemonik.json");
991
+ try {
992
+ const stat = await lstat(path);
993
+ if (stat.isSymbolicLink())
994
+ return { kind: "malformed", detail: "symlink" };
995
+ if (!stat.isFile())
996
+ return { kind: "malformed", detail: "identity path is not a regular file" };
997
+ const text = await readFile(path, "utf8");
998
+ if ((options.selectedRoot || options.configurationOnlyAbsent) && isConfigurationOnly(text))
999
+ return { kind: "absent" };
1000
+ return parseIdentityFile(text);
1001
+ } catch (error) {
1002
+ if (error.code === "ENOENT")
1003
+ return { kind: "absent" };
1004
+ return { kind: "malformed", detail: `cannot read identity file: ${error.message}` };
1005
+ }
1006
+ }
1007
+
918
1008
  // node_modules/web-tree-sitter/web-tree-sitter.js
919
1009
  var __defProp2 = Object.defineProperty;
920
1010
  var __name = (target, value) => __defProp2(target, "name", { value, configurable: true });
@@ -4959,9 +5049,9 @@ var Query = class {
4959
5049
  };
4960
5050
 
4961
5051
  // packages/shared/dist/ast/grammars.js
4962
- import { dirname, extname, join } from "node:path";
5052
+ import { dirname, extname, join as join2 } from "node:path";
4963
5053
  import { fileURLToPath } from "node:url";
4964
- var WASM_DIR = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
5054
+ var WASM_DIR = join2(dirname(fileURLToPath(import.meta.url)), "..", "..", "wasm");
4965
5055
 
4966
5056
  // packages/shared/dist/ast/astChunker.js
4967
5057
  var MAX_AST_PARSE_BYTES = 2 * 1024 * 1024;
@@ -5147,96 +5237,8 @@ var REPOSITORY_PROVIDER_RULES = Object.freeze([
5147
5237
  ]);
5148
5238
  var controls = new RegExp("\\p{Cc}", "u");
5149
5239
 
5150
- // packages/shared/dist/projectIdentityFile.js
5151
- import { lstat, readFile } from "node:fs/promises";
5152
- import { join as join2 } from "node:path";
5153
- var 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}$/;
5154
- var isCanonicalUuid = (value) => typeof value === "string" && CANONICAL_UUID.test(value);
5155
- var IDENTITY_KEYS = /* @__PURE__ */ new Set([
5156
- "schemaVersion",
5157
- "projectId",
5158
- "projectName",
5159
- "repositoryFingerprint"
5160
- ]);
5161
- var FINGERPRINT_KEYS = /* @__PURE__ */ new Set(["algorithmVersion", "hash"]);
5162
- function parseIdentityFile(text) {
5163
- let value;
5164
- try {
5165
- value = JSON.parse(text);
5166
- } catch (error) {
5167
- return { kind: "malformed", detail: `unparseable JSON: ${error.message}` };
5168
- }
5169
- if (!value || typeof value !== "object" || Array.isArray(value)) {
5170
- return { kind: "malformed", detail: "identity file must contain a JSON object" };
5171
- }
5172
- const record = value;
5173
- if (record.schemaVersion !== 1) {
5174
- return { kind: "unknown_version", version: record.schemaVersion };
5175
- }
5176
- const unknownKey = Object.keys(record).find((key) => !IDENTITY_KEYS.has(key));
5177
- if (unknownKey)
5178
- return { kind: "malformed", detail: `unknown key "${unknownKey}"` };
5179
- if (!isCanonicalUuid(record.projectId)) {
5180
- return { kind: "malformed", detail: '"projectId" must be a canonical RFC 4122 UUID string' };
5181
- }
5182
- if ("projectName" in record && typeof record.projectName !== "string") {
5183
- return { kind: "malformed", detail: '"projectName" must be a string when present' };
5184
- }
5185
- if ("repositoryFingerprint" in record && (!record.repositoryFingerprint || typeof record.repositoryFingerprint !== "object" || Array.isArray(record.repositoryFingerprint))) {
5186
- return { kind: "malformed", detail: '"repositoryFingerprint" must be an object when present' };
5187
- }
5188
- const fingerprint = record.repositoryFingerprint;
5189
- const unknownFingerprintKey = fingerprint ? Object.keys(fingerprint).find((key) => !FINGERPRINT_KEYS.has(key)) : void 0;
5190
- if (unknownFingerprintKey) {
5191
- return {
5192
- kind: "malformed",
5193
- detail: `unknown repositoryFingerprint key "${unknownFingerprintKey}"`
5194
- };
5195
- }
5196
- if (fingerprint && (fingerprint.algorithmVersion !== 1 || typeof fingerprint.hash !== "string")) {
5197
- return {
5198
- kind: "malformed",
5199
- detail: '"repositoryFingerprint" must contain algorithmVersion 1 and a string hash'
5200
- };
5201
- }
5202
- const repositoryFingerprint = fingerprint ? { algorithmVersion: 1, hash: fingerprint.hash } : void 0;
5203
- return {
5204
- kind: "ok",
5205
- identity: {
5206
- schemaVersion: 1,
5207
- projectId: record.projectId,
5208
- ...record.projectName === void 0 ? {} : { projectName: record.projectName },
5209
- ...repositoryFingerprint ? { repositoryFingerprint } : {}
5210
- }
5211
- };
5212
- }
5213
- async function readIdentityFile(dir, options = {}) {
5214
- const path = join2(dir, ".mnemonik.json");
5215
- try {
5216
- const stat = await lstat(path);
5217
- if (stat.isSymbolicLink())
5218
- return { kind: "malformed", detail: "symlink" };
5219
- if (!stat.isFile())
5220
- return { kind: "malformed", detail: "identity path is not a regular file" };
5221
- const text = await readFile(path, "utf8");
5222
- if (options.selectedRoot) {
5223
- try {
5224
- const value = JSON.parse(text);
5225
- if (value && typeof value === "object" && !Array.isArray(value) && !("projectId" in value) && (!("schemaVersion" in value) || value.schemaVersion === 1))
5226
- return { kind: "absent" };
5227
- } catch {
5228
- }
5229
- }
5230
- return parseIdentityFile(text);
5231
- } catch (error) {
5232
- if (error.code === "ENOENT")
5233
- return { kind: "absent" };
5234
- return { kind: "malformed", detail: `cannot read identity file: ${error.message}` };
5235
- }
5236
- }
5237
-
5238
5240
  // packages/shared/dist/repositoryRoot.js
5239
- import { lstat as lstat2, readFile as readFile2 } from "node:fs/promises";
5241
+ import { lstat as lstat2, readFile as readFile2, realpath } from "node:fs/promises";
5240
5242
  import { execFile } from "node:child_process";
5241
5243
  import { homedir } from "node:os";
5242
5244
  import { dirname as dirname2, join as join3, resolve } from "node:path";
@@ -5298,7 +5300,7 @@ async function confirmedBoundaryAt(path) {
5298
5300
  async function boundariesBetween(cwd, root) {
5299
5301
  const boundaries = [];
5300
5302
  let directory = cwd;
5301
- while (directory !== root) {
5303
+ while (!samePath(directory, root)) {
5302
5304
  const boundary = await confirmedBoundaryAt(directory);
5303
5305
  if (boundary)
5304
5306
  boundaries.push(boundary);
@@ -5321,37 +5323,31 @@ async function containingRepository(root) {
5321
5323
  directory = parent;
5322
5324
  }
5323
5325
  }
5324
- async function canonicalBoundaryRoot(boundary) {
5325
- if (boundary.kind === "directory")
5326
- return boundary.path;
5327
- const pointer = /^gitdir:\s*(.+)\s*$/im.exec(await readFile2(join3(boundary.path, ".git"), "utf8"))?.[1];
5328
- if (!pointer)
5329
- return boundary.path;
5330
- const gitDir = resolve(boundary.path, pointer);
5331
- try {
5332
- const commonDir = resolve(gitDir, (await readFile2(join3(gitDir, "commondir"), "utf8")).trim());
5333
- return dirname2(commonDir);
5334
- } catch (error) {
5335
- if (error.code === "ENOENT")
5336
- return boundary.path;
5337
- throw error;
5338
- }
5326
+ async function canonicalPath(path) {
5327
+ const absolute = resolve(path);
5328
+ return realpath(absolute).catch(() => absolute);
5329
+ }
5330
+ function samePath(left, right) {
5331
+ return process.platform === "win32" ? left.toLowerCase() === right.toLowerCase() : left === right;
5339
5332
  }
5340
5333
  async function resolveRepositoryRoot(cwd) {
5341
- const absoluteCwd = resolve(cwd);
5334
+ const absoluteCwd = await canonicalPath(cwd);
5342
5335
  try {
5343
5336
  const { stdout } = await runGit(absoluteCwd, [
5344
5337
  "rev-parse",
5345
5338
  "--show-toplevel",
5339
+ "--git-dir",
5346
5340
  "--git-common-dir"
5347
5341
  ]);
5348
- const [rootLine, commonLine, ...extra] = stdout.trim().split(/\r?\n/);
5349
- if (!rootLine || !commonLine || extra.length) {
5342
+ const [rootLine, gitDirLine, commonLine, ...extra] = stdout.trim().split(/\r?\n/);
5343
+ if (!rootLine || !gitDirLine || !commonLine || extra.length) {
5350
5344
  return { kind: "git_unavailable", detail: "git rev-parse returned an unexpected response" };
5351
5345
  }
5352
- const root = resolve(rootLine);
5353
- const commonDir = resolve(root, commonLine);
5354
- const isLinkedWorktree = commonDir !== join3(root, ".git");
5346
+ const fromGit = (line) => canonicalPath(resolve(absoluteCwd, line));
5347
+ const root = await fromGit(rootLine);
5348
+ const gitDir = await fromGit(gitDirLine);
5349
+ const commonDir = await fromGit(commonLine);
5350
+ const isLinkedWorktree = !samePath(gitDir, commonDir);
5355
5351
  const nested = await boundariesBetween(absoluteCwd, root);
5356
5352
  if (!isLinkedWorktree && await containingRepository(root)) {
5357
5353
  const boundary = await boundaryAt(root);
@@ -5373,14 +5369,41 @@ async function resolveRepositoryRoot(cwd) {
5373
5369
  return { kind: "git_unavailable", detail: failure.message };
5374
5370
  }
5375
5371
  }
5372
+ async function linkedWorktreeCommonDir(dir) {
5373
+ try {
5374
+ if (!(await lstat2(join3(dir, ".git"))).isFile())
5375
+ return void 0;
5376
+ const pointer = /^gitdir:\s*(.+?)\s*$/im.exec(await readFile2(join3(dir, ".git"), "utf8"))?.[1];
5377
+ if (!pointer)
5378
+ return void 0;
5379
+ const gitDir = resolve(dir, pointer);
5380
+ const common = (await readFile2(join3(gitDir, "commondir"), "utf8")).trim();
5381
+ return common ? await canonicalPath(resolve(gitDir, common)) : void 0;
5382
+ } catch {
5383
+ return void 0;
5384
+ }
5385
+ }
5386
+ async function mainCheckout(worktreeTop, commonDir) {
5387
+ try {
5388
+ const { stdout } = await runGit(worktreeTop, ["worktree", "list", "--porcelain"]);
5389
+ const first = stdout.split(/\r?\n\r?\n/)[0] ?? "";
5390
+ const path = /^worktree (.+)$/m.exec(first)?.[1];
5391
+ if (path) {
5392
+ const main = await canonicalPath(resolve(worktreeTop, path));
5393
+ return /^bare$/m.test(first) ? dirname2(main) : main;
5394
+ }
5395
+ } catch {
5396
+ }
5397
+ return dirname2(commonDir);
5398
+ }
5376
5399
  async function readPlainIdentity(start2) {
5377
- const home = resolve(homedir());
5400
+ const home = await canonicalPath(homedir());
5378
5401
  let directory = start2;
5379
5402
  while (true) {
5380
- const result = await readIdentityFile(directory);
5403
+ const result = await readIdentityFile(directory, { configurationOnlyAbsent: true });
5381
5404
  if (result.kind !== "absent")
5382
5405
  return { root: directory, result };
5383
- if (directory === home)
5406
+ if (samePath(directory, home))
5384
5407
  break;
5385
5408
  const parent = dirname2(directory);
5386
5409
  if (parent === directory)
@@ -5389,58 +5412,72 @@ async function readPlainIdentity(start2) {
5389
5412
  }
5390
5413
  return { root: start2, result: { kind: "absent" } };
5391
5414
  }
5415
+ async function nearestIdentity(start2) {
5416
+ const home = await canonicalPath(homedir());
5417
+ let directory = start2;
5418
+ while (true) {
5419
+ const commonDir = await linkedWorktreeCommonDir(directory);
5420
+ if (commonDir)
5421
+ return { worktreeTop: directory, commonDir };
5422
+ const result = await readIdentityFile(directory, { configurationOnlyAbsent: true });
5423
+ if (result.kind !== "absent")
5424
+ return { root: directory, result };
5425
+ if (samePath(directory, home))
5426
+ return void 0;
5427
+ const parent = dirname2(directory);
5428
+ if (parent === directory)
5429
+ return void 0;
5430
+ directory = parent;
5431
+ }
5432
+ }
5433
+ async function resolveNearestProjectIdentity(cwd) {
5434
+ const start2 = await canonicalPath(cwd);
5435
+ const resolved = await resolveRepositoryRoot(start2);
5436
+ const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: start2 } : resolved;
5437
+ const nested = repository.kind === "git" ? repository.nested : [];
5438
+ let found = await nearestIdentity(start2);
5439
+ if (found && "worktreeTop" in found) {
5440
+ found = await readPlainIdentity(await mainCheckout(found.worktreeTop, found.commonDir));
5441
+ }
5442
+ if (found) {
5443
+ return shapedIdentity(found, await projectFolderRepository(found.root, repository), nested);
5444
+ }
5445
+ return { ...withBase(repository, repository.root, nested), kind: "absent" };
5446
+ }
5447
+ async function resolveNamedProjectIdentity(cwd, options) {
5448
+ const start2 = await canonicalPath(cwd);
5449
+ const resolved = await resolveRepositoryRoot(start2);
5450
+ const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: start2 } : resolved;
5451
+ const commonDir = await linkedWorktreeCommonDir(start2);
5452
+ const root = commonDir ? await mainCheckout(start2, commonDir) : start2;
5453
+ return shapedIdentity({ root, result: await readIdentityFile(root, options) }, await projectFolderRepository(root, repository), repository.kind === "git" ? repository.nested : []);
5454
+ }
5455
+ function shapedIdentity(found, repository, nested) {
5456
+ const base = withBase(repository, found.root, nested);
5457
+ if (found.result.kind === "ok")
5458
+ return { ...base, ...found.result };
5459
+ if (found.result.kind === "unknown_version")
5460
+ return { ...base, ...found.result, path: found.root };
5461
+ if (found.result.kind === "malformed")
5462
+ return { ...base, ...found.result, path: found.root };
5463
+ return { ...base, kind: "absent" };
5464
+ }
5465
+ async function projectFolderRepository(projectRoot, known) {
5466
+ if (known.kind === "git" && samePath(known.root, projectRoot))
5467
+ return known;
5468
+ const repository = await resolveRepositoryRoot(projectRoot);
5469
+ if (repository.kind === "git" && samePath(repository.root, projectRoot))
5470
+ return repository;
5471
+ return { kind: "plain", root: projectRoot };
5472
+ }
5392
5473
  function withBase(repository, root, nested) {
5393
5474
  return { root, repository, nested };
5394
5475
  }
5395
5476
  async function resolveProjectIdentity(cwd, options = {}) {
5396
- const resolved = await resolveRepositoryRoot(cwd);
5397
- const repository = resolved.kind === "git_unavailable" ? { kind: "plain", root: resolve(cwd) } : resolved;
5398
- if (repository.kind === "plain") {
5399
- const { root, result } = options.selectedRoot ? { root: repository.root, result: await readIdentityFile(repository.root, options) } : await readPlainIdentity(repository.root);
5400
- const base2 = withBase(repository, root, []);
5401
- if (result.kind === "ok")
5402
- return { ...base2, ...result };
5403
- if (result.kind === "unknown_version")
5404
- return { ...base2, ...result, path: root };
5405
- if (result.kind === "malformed")
5406
- return { ...base2, ...result, path: root };
5407
- return { ...base2, kind: "absent" };
5408
- }
5409
- const ownRoot = repository.isLinkedWorktree ? dirname2(repository.commonDir) : repository.root;
5410
- const outer = repository.isLinkedWorktree ? void 0 : await containingRepository(repository.root);
5411
- const own = await readIdentityFile(ownRoot, options);
5412
- if (!outer || options.selectedRoot || own.kind === "ok") {
5413
- const base2 = withBase(repository, ownRoot, repository.nested);
5414
- if (own.kind === "ok")
5415
- return { ...base2, ...own };
5416
- if (own.kind === "unknown_version")
5417
- return { ...base2, ...own, path: ownRoot };
5418
- if (own.kind === "malformed")
5419
- return { ...base2, ...own, path: ownRoot };
5420
- return { ...base2, kind: "absent" };
5421
- }
5422
- const nested = repository.nested;
5423
- const parentRoot = await canonicalBoundaryRoot(outer);
5424
- const parent = await readIdentityFile(parentRoot);
5425
- const base = withBase(repository, parentRoot, nested);
5426
- if (own.kind === "unknown_version")
5427
- return { ...base, ...own, path: ownRoot };
5428
- if (own.kind === "malformed")
5429
- return { ...base, ...own, path: ownRoot };
5430
- if (parent.kind === "unknown_version")
5431
- return { ...base, ...parent, path: parentRoot };
5432
- if (parent.kind === "malformed")
5433
- return { ...base, ...parent, path: parentRoot };
5434
- if (!options.allowNestedInherit) {
5435
- return {
5436
- ...base,
5437
- kind: "nested",
5438
- ...parent.kind === "ok" ? { parentIdentity: parent.identity } : {}
5439
- };
5477
+ if (options.selectedRoot || options.namedRoot) {
5478
+ return resolveNamedProjectIdentity(cwd, { selectedRoot: options.selectedRoot });
5440
5479
  }
5441
- if (parent.kind === "ok")
5442
- return { ...base, kind: "ok", identity: parent.identity };
5443
- return { ...base, kind: "absent" };
5480
+ return resolveNearestProjectIdentity(cwd);
5444
5481
  }
5445
5482
 
5446
5483
  // packages/shared/dist/apiOrigin.js