morphix-env 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -1
- package/dist/SKILL.md +4 -0
- package/dist/cli.js +565 -145
- package/dist/index.js +32 -10
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -831,8 +831,8 @@ var require_react_development = __commonJS({
|
|
|
831
831
|
function lazyInitializer(payload) {
|
|
832
832
|
if (-1 === payload._status) {
|
|
833
833
|
var resolveDebugValue = null, rejectDebugValue = null, ioInfo = payload._ioInfo;
|
|
834
|
-
null != ioInfo && (ioInfo.start = ioInfo.end = performance.now(), ioInfo.value = new Promise(function(
|
|
835
|
-
resolveDebugValue =
|
|
834
|
+
null != ioInfo && (ioInfo.start = ioInfo.end = performance.now(), ioInfo.value = new Promise(function(resolve8, reject) {
|
|
835
|
+
resolveDebugValue = resolve8;
|
|
836
836
|
rejectDebugValue = reject;
|
|
837
837
|
}));
|
|
838
838
|
ioInfo = payload._result;
|
|
@@ -948,21 +948,21 @@ var require_react_development = __commonJS({
|
|
|
948
948
|
);
|
|
949
949
|
actScopeDepth = prevActScopeDepth;
|
|
950
950
|
}
|
|
951
|
-
function recursivelyFlushAsyncActWork(returnValue,
|
|
951
|
+
function recursivelyFlushAsyncActWork(returnValue, resolve8, reject) {
|
|
952
952
|
var queue = ReactSharedInternals.actQueue;
|
|
953
953
|
if (null !== queue)
|
|
954
954
|
if (0 !== queue.length)
|
|
955
955
|
try {
|
|
956
956
|
flushActQueue(queue);
|
|
957
957
|
enqueueTask(function() {
|
|
958
|
-
return recursivelyFlushAsyncActWork(returnValue,
|
|
958
|
+
return recursivelyFlushAsyncActWork(returnValue, resolve8, reject);
|
|
959
959
|
});
|
|
960
960
|
return;
|
|
961
961
|
} catch (error) {
|
|
962
962
|
ReactSharedInternals.thrownErrors.push(error);
|
|
963
963
|
}
|
|
964
964
|
else ReactSharedInternals.actQueue = null;
|
|
965
|
-
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) :
|
|
965
|
+
0 < ReactSharedInternals.thrownErrors.length ? (queue = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, reject(queue)) : resolve8(returnValue);
|
|
966
966
|
}
|
|
967
967
|
function flushActQueue(queue) {
|
|
968
968
|
if (!isFlushing) {
|
|
@@ -1150,7 +1150,7 @@ var require_react_development = __commonJS({
|
|
|
1150
1150
|
));
|
|
1151
1151
|
});
|
|
1152
1152
|
return {
|
|
1153
|
-
then: function(
|
|
1153
|
+
then: function(resolve8, reject) {
|
|
1154
1154
|
didAwaitActCall = true;
|
|
1155
1155
|
thenable.then(
|
|
1156
1156
|
function(returnValue) {
|
|
@@ -1160,7 +1160,7 @@ var require_react_development = __commonJS({
|
|
|
1160
1160
|
flushActQueue(queue), enqueueTask(function() {
|
|
1161
1161
|
return recursivelyFlushAsyncActWork(
|
|
1162
1162
|
returnValue,
|
|
1163
|
-
|
|
1163
|
+
resolve8,
|
|
1164
1164
|
reject
|
|
1165
1165
|
);
|
|
1166
1166
|
});
|
|
@@ -1174,7 +1174,7 @@ var require_react_development = __commonJS({
|
|
|
1174
1174
|
ReactSharedInternals.thrownErrors.length = 0;
|
|
1175
1175
|
reject(_thrownError);
|
|
1176
1176
|
}
|
|
1177
|
-
} else
|
|
1177
|
+
} else resolve8(returnValue);
|
|
1178
1178
|
},
|
|
1179
1179
|
function(error) {
|
|
1180
1180
|
popActScope(prevActQueue, prevActScopeDepth);
|
|
@@ -1196,15 +1196,15 @@ var require_react_development = __commonJS({
|
|
|
1196
1196
|
if (0 < ReactSharedInternals.thrownErrors.length)
|
|
1197
1197
|
throw callback = aggregateErrors(ReactSharedInternals.thrownErrors), ReactSharedInternals.thrownErrors.length = 0, callback;
|
|
1198
1198
|
return {
|
|
1199
|
-
then: function(
|
|
1199
|
+
then: function(resolve8, reject) {
|
|
1200
1200
|
didAwaitActCall = true;
|
|
1201
1201
|
0 === prevActScopeDepth ? (ReactSharedInternals.actQueue = queue, enqueueTask(function() {
|
|
1202
1202
|
return recursivelyFlushAsyncActWork(
|
|
1203
1203
|
returnValue$jscomp$0,
|
|
1204
|
-
|
|
1204
|
+
resolve8,
|
|
1205
1205
|
reject
|
|
1206
1206
|
);
|
|
1207
|
-
})) :
|
|
1207
|
+
})) : resolve8(returnValue$jscomp$0);
|
|
1208
1208
|
}
|
|
1209
1209
|
};
|
|
1210
1210
|
};
|
|
@@ -12991,7 +12991,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
12991
12991
|
};
|
|
12992
12992
|
}
|
|
12993
12993
|
exports2.prerender = function(children, options) {
|
|
12994
|
-
return new Promise(function(
|
|
12994
|
+
return new Promise(function(resolve8, reject) {
|
|
12995
12995
|
var onHeaders = options ? options.onHeaders : void 0, onHeadersImpl;
|
|
12996
12996
|
onHeaders && (onHeadersImpl = function(headersDescriptor) {
|
|
12997
12997
|
onHeaders(new Headers(headersDescriptor));
|
|
@@ -13035,7 +13035,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13035
13035
|
{ highWaterMark: 0 }
|
|
13036
13036
|
);
|
|
13037
13037
|
stream2 = { postponed: getPostponedState(request), prelude: stream2 };
|
|
13038
|
-
|
|
13038
|
+
resolve8(stream2);
|
|
13039
13039
|
},
|
|
13040
13040
|
void 0,
|
|
13041
13041
|
void 0,
|
|
@@ -13046,7 +13046,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13046
13046
|
});
|
|
13047
13047
|
};
|
|
13048
13048
|
exports2.prerenderToNodeStream = function(children, options) {
|
|
13049
|
-
return new Promise(function(
|
|
13049
|
+
return new Promise(function(resolve8, reject) {
|
|
13050
13050
|
var resumableState = createResumableState(
|
|
13051
13051
|
options ? options.identifierPrefix : void 0,
|
|
13052
13052
|
options ? options.unstable_externalRuntimeSrc : void 0,
|
|
@@ -13078,7 +13078,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13078
13078
|
postponed: getPostponedState(request),
|
|
13079
13079
|
prelude: readable
|
|
13080
13080
|
};
|
|
13081
|
-
|
|
13081
|
+
resolve8(readable);
|
|
13082
13082
|
},
|
|
13083
13083
|
void 0,
|
|
13084
13084
|
void 0,
|
|
@@ -13123,7 +13123,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13123
13123
|
};
|
|
13124
13124
|
};
|
|
13125
13125
|
exports2.renderToReadableStream = function(children, options) {
|
|
13126
|
-
return new Promise(function(
|
|
13126
|
+
return new Promise(function(resolve8, reject) {
|
|
13127
13127
|
var onFatalError, onAllReady, allReady = new Promise(function(res, rej) {
|
|
13128
13128
|
onAllReady = res;
|
|
13129
13129
|
onFatalError = rej;
|
|
@@ -13173,7 +13173,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13173
13173
|
{ highWaterMark: 0 }
|
|
13174
13174
|
);
|
|
13175
13175
|
stream2.allReady = allReady;
|
|
13176
|
-
|
|
13176
|
+
resolve8(stream2);
|
|
13177
13177
|
},
|
|
13178
13178
|
function(error) {
|
|
13179
13179
|
allReady.catch(function() {
|
|
@@ -13188,7 +13188,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13188
13188
|
});
|
|
13189
13189
|
};
|
|
13190
13190
|
exports2.resume = function(children, postponedState, options) {
|
|
13191
|
-
return new Promise(function(
|
|
13191
|
+
return new Promise(function(resolve8, reject) {
|
|
13192
13192
|
var onFatalError, onAllReady, allReady = new Promise(function(res, rej) {
|
|
13193
13193
|
onAllReady = res;
|
|
13194
13194
|
onFatalError = rej;
|
|
@@ -13226,7 +13226,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13226
13226
|
{ highWaterMark: 0 }
|
|
13227
13227
|
);
|
|
13228
13228
|
stream2.allReady = allReady;
|
|
13229
|
-
|
|
13229
|
+
resolve8(stream2);
|
|
13230
13230
|
},
|
|
13231
13231
|
function(error) {
|
|
13232
13232
|
allReady.catch(function() {
|
|
@@ -13240,7 +13240,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13240
13240
|
});
|
|
13241
13241
|
};
|
|
13242
13242
|
exports2.resumeAndPrerender = function(children, postponedState, options) {
|
|
13243
|
-
return new Promise(function(
|
|
13243
|
+
return new Promise(function(resolve8, reject) {
|
|
13244
13244
|
var request = resumeAndPrerenderRequest(
|
|
13245
13245
|
children,
|
|
13246
13246
|
postponedState,
|
|
@@ -13272,7 +13272,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13272
13272
|
{ highWaterMark: 0 }
|
|
13273
13273
|
);
|
|
13274
13274
|
stream2 = { postponed: getPostponedState(request), prelude: stream2 };
|
|
13275
|
-
|
|
13275
|
+
resolve8(stream2);
|
|
13276
13276
|
},
|
|
13277
13277
|
void 0,
|
|
13278
13278
|
void 0,
|
|
@@ -13283,7 +13283,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13283
13283
|
});
|
|
13284
13284
|
};
|
|
13285
13285
|
exports2.resumeAndPrerenderToNodeStream = function(children, postponedState, options) {
|
|
13286
|
-
return new Promise(function(
|
|
13286
|
+
return new Promise(function(resolve8, reject) {
|
|
13287
13287
|
var request = resumeAndPrerenderRequest(
|
|
13288
13288
|
children,
|
|
13289
13289
|
postponedState,
|
|
@@ -13304,7 +13304,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
13304
13304
|
}
|
|
13305
13305
|
}), writable = createFakeWritableFromReadable(readable);
|
|
13306
13306
|
readable = { postponed: getPostponedState(request), prelude: readable };
|
|
13307
|
-
|
|
13307
|
+
resolve8(readable);
|
|
13308
13308
|
},
|
|
13309
13309
|
void 0,
|
|
13310
13310
|
void 0,
|
|
@@ -28776,7 +28776,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28776
28776
|
ensureCorrectIsomorphicReactVersion();
|
|
28777
28777
|
ensureCorrectIsomorphicReactVersion();
|
|
28778
28778
|
exports2.prerender = function(children, options) {
|
|
28779
|
-
return new Promise(function(
|
|
28779
|
+
return new Promise(function(resolve8, reject) {
|
|
28780
28780
|
var onHeaders = options ? options.onHeaders : void 0, onHeadersImpl;
|
|
28781
28781
|
onHeaders && (onHeadersImpl = function(headersDescriptor) {
|
|
28782
28782
|
onHeaders(new Headers(headersDescriptor));
|
|
@@ -28825,7 +28825,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28825
28825
|
postponed: getPostponedState(request),
|
|
28826
28826
|
prelude: stream2
|
|
28827
28827
|
};
|
|
28828
|
-
|
|
28828
|
+
resolve8(stream2);
|
|
28829
28829
|
},
|
|
28830
28830
|
void 0,
|
|
28831
28831
|
void 0,
|
|
@@ -28836,7 +28836,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28836
28836
|
});
|
|
28837
28837
|
};
|
|
28838
28838
|
exports2.prerenderToNodeStream = function(children, options) {
|
|
28839
|
-
return new Promise(function(
|
|
28839
|
+
return new Promise(function(resolve8, reject) {
|
|
28840
28840
|
var resumableState = createResumableState(
|
|
28841
28841
|
options ? options.identifierPrefix : void 0,
|
|
28842
28842
|
options ? options.unstable_externalRuntimeSrc : void 0,
|
|
@@ -28868,7 +28868,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28868
28868
|
postponed: getPostponedState(request),
|
|
28869
28869
|
prelude: readable
|
|
28870
28870
|
};
|
|
28871
|
-
|
|
28871
|
+
resolve8(readable);
|
|
28872
28872
|
},
|
|
28873
28873
|
void 0,
|
|
28874
28874
|
void 0,
|
|
@@ -28913,7 +28913,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28913
28913
|
};
|
|
28914
28914
|
};
|
|
28915
28915
|
exports2.renderToReadableStream = function(children, options) {
|
|
28916
|
-
return new Promise(function(
|
|
28916
|
+
return new Promise(function(resolve8, reject) {
|
|
28917
28917
|
var onFatalError, onAllReady, allReady = new Promise(function(res, rej) {
|
|
28918
28918
|
onAllReady = res;
|
|
28919
28919
|
onFatalError = rej;
|
|
@@ -28963,7 +28963,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28963
28963
|
{ highWaterMark: 0 }
|
|
28964
28964
|
);
|
|
28965
28965
|
stream2.allReady = allReady;
|
|
28966
|
-
|
|
28966
|
+
resolve8(stream2);
|
|
28967
28967
|
},
|
|
28968
28968
|
function(error) {
|
|
28969
28969
|
allReady.catch(function() {
|
|
@@ -28978,7 +28978,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
28978
28978
|
});
|
|
28979
28979
|
};
|
|
28980
28980
|
exports2.resume = function(children, postponedState, options) {
|
|
28981
|
-
return new Promise(function(
|
|
28981
|
+
return new Promise(function(resolve8, reject) {
|
|
28982
28982
|
var onFatalError, onAllReady, allReady = new Promise(function(res, rej) {
|
|
28983
28983
|
onAllReady = res;
|
|
28984
28984
|
onFatalError = rej;
|
|
@@ -29016,7 +29016,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
29016
29016
|
{ highWaterMark: 0 }
|
|
29017
29017
|
);
|
|
29018
29018
|
stream2.allReady = allReady;
|
|
29019
|
-
|
|
29019
|
+
resolve8(stream2);
|
|
29020
29020
|
},
|
|
29021
29021
|
function(error) {
|
|
29022
29022
|
allReady.catch(function() {
|
|
@@ -29030,7 +29030,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
29030
29030
|
});
|
|
29031
29031
|
};
|
|
29032
29032
|
exports2.resumeAndPrerender = function(children, postponedState, options) {
|
|
29033
|
-
return new Promise(function(
|
|
29033
|
+
return new Promise(function(resolve8, reject) {
|
|
29034
29034
|
var request = resumeAndPrerenderRequest(
|
|
29035
29035
|
children,
|
|
29036
29036
|
postponedState,
|
|
@@ -29064,7 +29064,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
29064
29064
|
{ highWaterMark: 0 }
|
|
29065
29065
|
);
|
|
29066
29066
|
stream2 = { postponed: getPostponedState(request), prelude: stream2 };
|
|
29067
|
-
|
|
29067
|
+
resolve8(stream2);
|
|
29068
29068
|
},
|
|
29069
29069
|
void 0,
|
|
29070
29070
|
void 0,
|
|
@@ -29075,7 +29075,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
29075
29075
|
});
|
|
29076
29076
|
};
|
|
29077
29077
|
exports2.resumeAndPrerenderToNodeStream = function(children, postponedState, options) {
|
|
29078
|
-
return new Promise(function(
|
|
29078
|
+
return new Promise(function(resolve8, reject) {
|
|
29079
29079
|
var request = resumeAndPrerenderRequest(
|
|
29080
29080
|
children,
|
|
29081
29081
|
postponedState,
|
|
@@ -29099,7 +29099,7 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
|
|
|
29099
29099
|
postponed: getPostponedState(request),
|
|
29100
29100
|
prelude: readable
|
|
29101
29101
|
};
|
|
29102
|
-
|
|
29102
|
+
resolve8(readable);
|
|
29103
29103
|
},
|
|
29104
29104
|
void 0,
|
|
29105
29105
|
void 0,
|
|
@@ -29482,9 +29482,9 @@ var require_jsx_runtime = __commonJS({
|
|
|
29482
29482
|
|
|
29483
29483
|
// src/cli.ts
|
|
29484
29484
|
var import_cross_spawn = __toESM(require("cross-spawn"));
|
|
29485
|
-
var
|
|
29486
|
-
var
|
|
29487
|
-
var
|
|
29485
|
+
var import_fs11 = require("fs");
|
|
29486
|
+
var import_os8 = require("os");
|
|
29487
|
+
var import_path11 = require("path");
|
|
29488
29488
|
|
|
29489
29489
|
// src/audit.ts
|
|
29490
29490
|
var import_fs = require("fs");
|
|
@@ -29603,12 +29603,6 @@ function validateConfig(config, label = CONFIG_FILE) {
|
|
|
29603
29603
|
return errors;
|
|
29604
29604
|
}
|
|
29605
29605
|
|
|
29606
|
-
// src/sources.ts
|
|
29607
|
-
var import_child_process2 = require("child_process");
|
|
29608
|
-
var import_fs5 = require("fs");
|
|
29609
|
-
var import_path5 = require("path");
|
|
29610
|
-
var import_dotenv3 = require("dotenv");
|
|
29611
|
-
|
|
29612
29606
|
// src/env.ts
|
|
29613
29607
|
var import_fs3 = require("fs");
|
|
29614
29608
|
var import_path3 = require("path");
|
|
@@ -29618,6 +29612,14 @@ function parseEnvFile(filePath) {
|
|
|
29618
29612
|
if (!(0, import_fs3.existsSync)(absPath)) return {};
|
|
29619
29613
|
return (0, import_dotenv.parse)((0, import_fs3.readFileSync)(absPath, "utf8"));
|
|
29620
29614
|
}
|
|
29615
|
+
function isDotenvxEncrypted(filePath) {
|
|
29616
|
+
try {
|
|
29617
|
+
const content = (0, import_fs3.readFileSync)((0, import_path3.resolve)(filePath), "utf8");
|
|
29618
|
+
return content.includes("DOTENV_PUBLIC_KEY") && /^[A-Za-z_][A-Za-z0-9_]*="?encrypted:/m.test(content);
|
|
29619
|
+
} catch {
|
|
29620
|
+
return false;
|
|
29621
|
+
}
|
|
29622
|
+
}
|
|
29621
29623
|
var PUBLIC_PREFIXES = ["NEXT_PUBLIC_", "VITE_", "EXPO_PUBLIC_"];
|
|
29622
29624
|
function extractPublicVars(environment = process.env) {
|
|
29623
29625
|
const vars = {};
|
|
@@ -29629,6 +29631,12 @@ function extractPublicVars(environment = process.env) {
|
|
|
29629
29631
|
return vars;
|
|
29630
29632
|
}
|
|
29631
29633
|
|
|
29634
|
+
// src/sources.ts
|
|
29635
|
+
var import_child_process2 = require("child_process");
|
|
29636
|
+
var import_fs5 = require("fs");
|
|
29637
|
+
var import_path5 = require("path");
|
|
29638
|
+
var import_dotenv3 = require("dotenv");
|
|
29639
|
+
|
|
29632
29640
|
// src/infisical.ts
|
|
29633
29641
|
var import_sdk = require("@infisical/sdk");
|
|
29634
29642
|
var import_child_process = require("child_process");
|
|
@@ -29739,7 +29747,7 @@ function assertSafeGlobalFile(file, context, entry) {
|
|
|
29739
29747
|
if ((mode & 63) !== 0) {
|
|
29740
29748
|
throw new SourceError(
|
|
29741
29749
|
entry.name,
|
|
29742
|
-
|
|
29750
|
+
entry.source.provider,
|
|
29743
29751
|
`[morphix-env] Global env file ${file} is readable by group or other users; set mode 0600 or pass --allow-insecure-global.`
|
|
29744
29752
|
);
|
|
29745
29753
|
}
|
|
@@ -29831,6 +29839,16 @@ function resolveDotenvx(entry, source, context) {
|
|
|
29831
29839
|
if (existingFiles.length !== files.length) {
|
|
29832
29840
|
throw new SourceError(entry.name, source.provider, `[morphix-env] dotenvx source "${entry.name}" is missing a declared env file.`);
|
|
29833
29841
|
}
|
|
29842
|
+
if (entry.globalImplicit && !context.allowInsecureGlobal && process.platform !== "win32") {
|
|
29843
|
+
const keysFile = (0, import_path5.join)((0, import_path5.dirname)(existingFiles[0]), ".env.keys");
|
|
29844
|
+
if ((0, import_fs5.existsSync)(keysFile) && ((0, import_fs5.statSync)(keysFile).mode & 63) !== 0) {
|
|
29845
|
+
throw new SourceError(
|
|
29846
|
+
entry.name,
|
|
29847
|
+
source.provider,
|
|
29848
|
+
`[morphix-env] Global dotenvx keys file ${keysFile} is readable by group or other users; set mode 0600 or pass --allow-insecure-global.`
|
|
29849
|
+
);
|
|
29850
|
+
}
|
|
29851
|
+
}
|
|
29834
29852
|
const command = ensureCommand("dotenvx", entry.name, source.provider);
|
|
29835
29853
|
const keys = [...new Set(existingFiles.flatMap((file) => Object.keys(parseEnvFile(file))))].filter((key) => !key.startsWith("DOTENV_PUBLIC_KEY"));
|
|
29836
29854
|
if (!keys.length) return { name: entry.name, provider: source.provider, values: {}, availability: "loaded" };
|
|
@@ -29838,8 +29856,10 @@ function resolveDotenvx(entry, source, context) {
|
|
|
29838
29856
|
let stage = "run";
|
|
29839
29857
|
try {
|
|
29840
29858
|
const output = (0, import_child_process2.execFileSync)(
|
|
29859
|
+
// --overload aligns dotenvx with every other provider: composed file
|
|
29860
|
+
// values win over same-named variables already in the parent env.
|
|
29841
29861
|
command,
|
|
29842
|
-
["run", "-f", existingFiles.join(","), "--", process.execPath, "-e", helper, JSON.stringify(keys)],
|
|
29862
|
+
["run", "--overload", "-f", existingFiles.join(","), "--", process.execPath, "-e", helper, JSON.stringify(keys)],
|
|
29843
29863
|
{
|
|
29844
29864
|
encoding: "utf8",
|
|
29845
29865
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -29862,7 +29882,8 @@ function resolveDotenvx(entry, source, context) {
|
|
|
29862
29882
|
return { name: entry.name, provider: source.provider, values, availability: "loaded" };
|
|
29863
29883
|
} catch (error) {
|
|
29864
29884
|
const category = typeof error?.code === "string" ? error.code : "failed";
|
|
29865
|
-
|
|
29885
|
+
const sniffHint = entry.globalImplicit ? " The global file looks dotenvx-encrypted; if it is actually plaintext, remove the DOTENV_PUBLIC_KEY / encrypted: markers." : "";
|
|
29886
|
+
throw new SourceError(entry.name, source.provider, `[morphix-env] dotenvx source "${entry.name}" could not decrypt or load (${stage}:${category}).${sniffHint}`);
|
|
29866
29887
|
}
|
|
29867
29888
|
}
|
|
29868
29889
|
var keytarModule;
|
|
@@ -30049,9 +30070,10 @@ function resolveEntries(layers, options) {
|
|
|
30049
30070
|
...includeGlobal ? Object.entries(layers.global.config.profiles || {}) : [],
|
|
30050
30071
|
...Object.entries(layers.project.config.profiles || {})
|
|
30051
30072
|
]);
|
|
30073
|
+
const globalEncrypted = isDotenvxEncrypted(layers.globalEnvFile);
|
|
30052
30074
|
const globalDotenv = includeGlobal ? [{
|
|
30053
30075
|
name: GLOBAL_DOTENV_SOURCE,
|
|
30054
|
-
source: { provider: "local", files: [layers.globalEnvFile], optional: true },
|
|
30076
|
+
source: globalEncrypted ? { provider: "dotenvx", files: [layers.globalEnvFile], optional: true } : { provider: "local", files: [layers.globalEnvFile], optional: true },
|
|
30055
30077
|
baseDir: layers.global.baseDir,
|
|
30056
30078
|
globalImplicit: true
|
|
30057
30079
|
}] : [];
|
|
@@ -37101,14 +37123,14 @@ async function startEditorServer(encodedState) {
|
|
|
37101
37123
|
});
|
|
37102
37124
|
const closeTimer = setTimeout(() => server.close(), EDITOR_LIFETIME_MS);
|
|
37103
37125
|
closeTimer.unref();
|
|
37104
|
-
await new Promise((
|
|
37126
|
+
await new Promise((resolve8, reject) => {
|
|
37105
37127
|
server.once("error", reject);
|
|
37106
37128
|
server.listen(0, "127.0.0.1", () => {
|
|
37107
37129
|
const address = server.address();
|
|
37108
37130
|
if (!address || typeof address === "string") return reject(new Error("Editor did not receive a loopback port"));
|
|
37109
37131
|
process.stdout.write(`http://127.0.0.1:${address.port}${editorPath(state)}
|
|
37110
37132
|
`);
|
|
37111
|
-
|
|
37133
|
+
resolve8();
|
|
37112
37134
|
});
|
|
37113
37135
|
});
|
|
37114
37136
|
}
|
|
@@ -37129,7 +37151,7 @@ async function launchEditor(entryScript, composition, selectedSource) {
|
|
|
37129
37151
|
detached: true,
|
|
37130
37152
|
stdio: ["ignore", "pipe", "ignore"]
|
|
37131
37153
|
});
|
|
37132
|
-
const url = await new Promise((
|
|
37154
|
+
const url = await new Promise((resolve8, reject) => {
|
|
37133
37155
|
const timer = setTimeout(() => reject(new Error("[morphix-env] Timed out starting local editor.")), 5e3);
|
|
37134
37156
|
child.once("error", () => {
|
|
37135
37157
|
clearTimeout(timer);
|
|
@@ -37139,7 +37161,7 @@ async function launchEditor(entryScript, composition, selectedSource) {
|
|
|
37139
37161
|
clearTimeout(timer);
|
|
37140
37162
|
const url2 = chunk.toString("utf8").trim();
|
|
37141
37163
|
child.stdout?.destroy();
|
|
37142
|
-
|
|
37164
|
+
resolve8(url2);
|
|
37143
37165
|
});
|
|
37144
37166
|
});
|
|
37145
37167
|
child.unref();
|
|
@@ -37154,6 +37176,267 @@ async function launchEditor(entryScript, composition, selectedSource) {
|
|
|
37154
37176
|
return { url, opened };
|
|
37155
37177
|
}
|
|
37156
37178
|
|
|
37179
|
+
// src/migrate.ts
|
|
37180
|
+
var import_child_process4 = require("child_process");
|
|
37181
|
+
var import_fs7 = require("fs");
|
|
37182
|
+
var import_os5 = require("os");
|
|
37183
|
+
var import_path7 = require("path");
|
|
37184
|
+
var import_dotenv4 = require("dotenv");
|
|
37185
|
+
function resolveUnitFile(rawFile, baseDir, homeDir) {
|
|
37186
|
+
const expanded = expandHomePath(rawFile, homeDir);
|
|
37187
|
+
return (0, import_path7.isAbsolute)(expanded) ? expanded : (0, import_path7.resolve)(baseDir, expanded);
|
|
37188
|
+
}
|
|
37189
|
+
function snapshotValues(unit) {
|
|
37190
|
+
const values = {};
|
|
37191
|
+
for (const file of unit.files) Object.assign(values, parseEnvFile(file));
|
|
37192
|
+
return values;
|
|
37193
|
+
}
|
|
37194
|
+
function declaredUnits(loaded, scope, homeDir) {
|
|
37195
|
+
const units = [];
|
|
37196
|
+
for (const [name, source] of Object.entries(loaded.config.sources || {})) {
|
|
37197
|
+
if (source.provider !== "local") continue;
|
|
37198
|
+
const files = source.files.map((file) => resolveUnitFile(file, loaded.baseDir, homeDir)).filter(import_fs7.existsSync);
|
|
37199
|
+
if (!files.length) continue;
|
|
37200
|
+
const probe = {
|
|
37201
|
+
name,
|
|
37202
|
+
kind: "declared",
|
|
37203
|
+
scope,
|
|
37204
|
+
baseDir: loaded.baseDir,
|
|
37205
|
+
configPath: loaded.path,
|
|
37206
|
+
source,
|
|
37207
|
+
files,
|
|
37208
|
+
keyNames: []
|
|
37209
|
+
};
|
|
37210
|
+
units.push({ ...probe, keyNames: Object.keys(snapshotValues(probe)).sort() });
|
|
37211
|
+
}
|
|
37212
|
+
return units;
|
|
37213
|
+
}
|
|
37214
|
+
function discoverPlaintextUnits(layers, homeDir = (0, import_os5.homedir)()) {
|
|
37215
|
+
const units = [];
|
|
37216
|
+
if ((0, import_fs7.existsSync)(layers.globalEnvFile) && !isDotenvxEncrypted(layers.globalEnvFile)) {
|
|
37217
|
+
const source = { provider: "local", files: [layers.globalEnvFile], optional: true };
|
|
37218
|
+
const probe = {
|
|
37219
|
+
name: GLOBAL_DOTENV_SOURCE,
|
|
37220
|
+
kind: "global-implicit",
|
|
37221
|
+
scope: null,
|
|
37222
|
+
baseDir: (0, import_path7.dirname)(layers.globalEnvFile),
|
|
37223
|
+
configPath: null,
|
|
37224
|
+
source,
|
|
37225
|
+
files: [layers.globalEnvFile],
|
|
37226
|
+
keyNames: []
|
|
37227
|
+
};
|
|
37228
|
+
units.push({ ...probe, keyNames: Object.keys(snapshotValues(probe)).sort() });
|
|
37229
|
+
}
|
|
37230
|
+
units.push(...declaredUnits(layers.global, "global", homeDir));
|
|
37231
|
+
units.push(...declaredUnits(layers.project, "project", homeDir));
|
|
37232
|
+
return units;
|
|
37233
|
+
}
|
|
37234
|
+
function legacyPlaintextHints(layers, units, homeDir = (0, import_os5.homedir)()) {
|
|
37235
|
+
const covered = new Set(units.flatMap((unit) => unit.files));
|
|
37236
|
+
const legacyFiles = layers.project.config.envFiles || [".env.local"];
|
|
37237
|
+
return legacyFiles.map((file) => resolveUnitFile(file, layers.project.baseDir, homeDir)).filter((file) => (0, import_fs7.existsSync)(file) && !covered.has(file) && !isDotenvxEncrypted(file));
|
|
37238
|
+
}
|
|
37239
|
+
function backupFile(file, stamp) {
|
|
37240
|
+
const backup = `${file}.mx-env-backup-${stamp}`;
|
|
37241
|
+
(0, import_fs7.copyFileSync)(file, backup);
|
|
37242
|
+
(0, import_fs7.chmodSync)(backup, 384);
|
|
37243
|
+
return backup;
|
|
37244
|
+
}
|
|
37245
|
+
var BACKUP_MARK = ".mx-env-backup-";
|
|
37246
|
+
function restoreBackups(backups) {
|
|
37247
|
+
const failed = [];
|
|
37248
|
+
for (const backup of backups) {
|
|
37249
|
+
const original = backup.slice(0, backup.lastIndexOf(BACKUP_MARK));
|
|
37250
|
+
try {
|
|
37251
|
+
if (original && (0, import_fs7.existsSync)(backup)) (0, import_fs7.copyFileSync)(backup, original);
|
|
37252
|
+
} catch {
|
|
37253
|
+
if (original) failed.push(original);
|
|
37254
|
+
}
|
|
37255
|
+
}
|
|
37256
|
+
return failed;
|
|
37257
|
+
}
|
|
37258
|
+
function withRestoreOutcome(message, failed, backups) {
|
|
37259
|
+
if (failed.length) {
|
|
37260
|
+
return `${message} RESTORE FAILED for: ${failed.join(", ")} \u2014 restore manually from the .mx-env-backup-* copies${backups.length ? ` (${backups.join(", ")})` : ""}.`;
|
|
37261
|
+
}
|
|
37262
|
+
return `${message} Plaintext and configuration were restored from backup${backups.length ? ` (${backups.join(", ")})` : ""}.`;
|
|
37263
|
+
}
|
|
37264
|
+
function equivalent(expected, actual) {
|
|
37265
|
+
const expectedKeys = Object.keys(expected).sort();
|
|
37266
|
+
const actualKeys = Object.keys(actual).sort();
|
|
37267
|
+
if (expectedKeys.length !== actualKeys.length) return false;
|
|
37268
|
+
return expectedKeys.every((key, index2) => key === actualKeys[index2] && expected[key] === actual[key]);
|
|
37269
|
+
}
|
|
37270
|
+
function existingDeclaredFiles(unit, homeDir) {
|
|
37271
|
+
const existing = new Set(unit.files);
|
|
37272
|
+
return unit.source.files.filter((file) => existing.has(resolveUnitFile(file, unit.baseDir, homeDir)));
|
|
37273
|
+
}
|
|
37274
|
+
function droppedDeclaredFiles(unit, homeDir) {
|
|
37275
|
+
const existing = new Set(unit.files);
|
|
37276
|
+
return unit.source.files.filter((file) => !existing.has(resolveUnitFile(file, unit.baseDir, homeDir)));
|
|
37277
|
+
}
|
|
37278
|
+
function rewriteDeclaredSource(unit, newSource, stamp, backups) {
|
|
37279
|
+
const configPath = unit.configPath;
|
|
37280
|
+
backups.push(backupFile(configPath, stamp));
|
|
37281
|
+
const parsed = JSON.parse((0, import_fs7.readFileSync)(configPath, "utf8"));
|
|
37282
|
+
parsed.sources[unit.name] = newSource;
|
|
37283
|
+
(0, import_fs7.writeFileSync)(configPath, `${JSON.stringify(parsed, null, 2)}
|
|
37284
|
+
`);
|
|
37285
|
+
}
|
|
37286
|
+
function gitIgnoreWarnings(paths) {
|
|
37287
|
+
const warnings = [];
|
|
37288
|
+
for (const path of paths) {
|
|
37289
|
+
try {
|
|
37290
|
+
(0, import_child_process4.execFileSync)("git", ["rev-parse", "--is-inside-work-tree"], { cwd: (0, import_path7.dirname)(path), stdio: ["ignore", "ignore", "ignore"] });
|
|
37291
|
+
} catch {
|
|
37292
|
+
continue;
|
|
37293
|
+
}
|
|
37294
|
+
try {
|
|
37295
|
+
(0, import_child_process4.execFileSync)("git", ["check-ignore", "-q", path], { cwd: (0, import_path7.dirname)(path), stdio: ["ignore", "ignore", "ignore"] });
|
|
37296
|
+
} catch (error) {
|
|
37297
|
+
if (error?.status === 1) {
|
|
37298
|
+
warnings.push(`[morphix-env] WARNING: ${path} is inside a git repository and NOT git-ignored \u2014 this file holds the decryption key and must never be committed.`);
|
|
37299
|
+
}
|
|
37300
|
+
}
|
|
37301
|
+
}
|
|
37302
|
+
return warnings;
|
|
37303
|
+
}
|
|
37304
|
+
async function reloadViaKeychain(unit, newSource, homeDir) {
|
|
37305
|
+
const entry = {
|
|
37306
|
+
name: unit.name,
|
|
37307
|
+
source: newSource,
|
|
37308
|
+
baseDir: unit.baseDir,
|
|
37309
|
+
globalImplicit: unit.kind === "global-implicit"
|
|
37310
|
+
};
|
|
37311
|
+
const loaded = await loadSource(entry, { homeDir, environment: { ...process.env } });
|
|
37312
|
+
return loaded.values;
|
|
37313
|
+
}
|
|
37314
|
+
function decryptValues(command, files) {
|
|
37315
|
+
const values = {};
|
|
37316
|
+
for (const file of files) {
|
|
37317
|
+
const output = (0, import_child_process4.execFileSync)(command, ["decrypt", "-f", file, "--stdout", "--no-native"], {
|
|
37318
|
+
encoding: "utf8",
|
|
37319
|
+
cwd: (0, import_path7.dirname)(file),
|
|
37320
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
37321
|
+
});
|
|
37322
|
+
const markerKeys = new Set(Object.keys(parseEnvFile(file)).filter((key) => key.startsWith("DOTENV_PUBLIC_KEY")));
|
|
37323
|
+
for (const [key, value] of Object.entries((0, import_dotenv4.parse)(output))) {
|
|
37324
|
+
if (!markerKeys.has(key)) values[key] = value;
|
|
37325
|
+
}
|
|
37326
|
+
}
|
|
37327
|
+
return values;
|
|
37328
|
+
}
|
|
37329
|
+
async function migrateToDotenvx(unit, stamp, homeDir, backups) {
|
|
37330
|
+
const snapshot = snapshotValues(unit);
|
|
37331
|
+
for (const file of unit.files) backups.push(backupFile(file, stamp));
|
|
37332
|
+
const candidateKeysFiles = [...new Set(unit.files.map((file) => (0, import_path7.join)((0, import_path7.dirname)(file), ".env.keys")))];
|
|
37333
|
+
const preExistingKeys = new Set(candidateKeysFiles.filter(import_fs7.existsSync));
|
|
37334
|
+
for (const keysFile of preExistingKeys) backups.push(backupFile(keysFile, stamp));
|
|
37335
|
+
try {
|
|
37336
|
+
let command;
|
|
37337
|
+
try {
|
|
37338
|
+
command = ensureCommand("dotenvx", unit.name, "dotenvx");
|
|
37339
|
+
} catch {
|
|
37340
|
+
throw new Error("the dotenvx CLI is required; install it (e.g. `npm i -g @dotenvx/dotenvx`) or migrate to another target.");
|
|
37341
|
+
}
|
|
37342
|
+
for (const file of unit.files) {
|
|
37343
|
+
(0, import_child_process4.execFileSync)(command, ["encrypt", "-f", file, "--no-native"], { cwd: (0, import_path7.dirname)(file), stdio: ["ignore", "ignore", "ignore"] });
|
|
37344
|
+
const keysFile = (0, import_path7.join)((0, import_path7.dirname)(file), ".env.keys");
|
|
37345
|
+
if ((0, import_fs7.existsSync)(keysFile)) (0, import_fs7.chmodSync)(keysFile, 384);
|
|
37346
|
+
}
|
|
37347
|
+
const keysFiles = candidateKeysFiles.filter(import_fs7.existsSync);
|
|
37348
|
+
const values = decryptValues(command, unit.files);
|
|
37349
|
+
if (!equivalent(snapshot, values)) {
|
|
37350
|
+
throw new Error("post-migration verification failed: decrypted values differ from the plaintext snapshot.");
|
|
37351
|
+
}
|
|
37352
|
+
const warnings = [];
|
|
37353
|
+
if (unit.kind === "declared") {
|
|
37354
|
+
const newSource = {
|
|
37355
|
+
provider: "dotenvx",
|
|
37356
|
+
files: existingDeclaredFiles(unit, homeDir),
|
|
37357
|
+
...unit.source.override ? { override: true } : {},
|
|
37358
|
+
...unit.source.optional ? { optional: true } : {}
|
|
37359
|
+
};
|
|
37360
|
+
rewriteDeclaredSource(unit, newSource, stamp, backups);
|
|
37361
|
+
for (const dropped of droppedDeclaredFiles(unit, homeDir)) {
|
|
37362
|
+
warnings.push(`[morphix-env] Warning: declared file "${dropped}" did not exist at migration time and was dropped from the rewritten source; re-add it to the config if it returns.`);
|
|
37363
|
+
}
|
|
37364
|
+
}
|
|
37365
|
+
return { warnings: [...warnings, ...gitIgnoreWarnings(keysFiles)] };
|
|
37366
|
+
} catch (error) {
|
|
37367
|
+
const failed = restoreBackups(backups);
|
|
37368
|
+
for (const keysFile of candidateKeysFiles) {
|
|
37369
|
+
if (!preExistingKeys.has(keysFile) && (0, import_fs7.existsSync)(keysFile)) (0, import_fs7.rmSync)(keysFile);
|
|
37370
|
+
}
|
|
37371
|
+
const message = error instanceof Error ? error.message : "unknown failure";
|
|
37372
|
+
throw new Error(withRestoreOutcome(message, failed, backups));
|
|
37373
|
+
}
|
|
37374
|
+
}
|
|
37375
|
+
function snapshotCovered(expected, actual) {
|
|
37376
|
+
return Object.keys(expected).every((key) => actual[key] === expected[key]);
|
|
37377
|
+
}
|
|
37378
|
+
async function migrateToKeychain(unit, service, stamp, homeDir, backups) {
|
|
37379
|
+
if (process.platform !== "darwin") throw new Error("the os-keychain target is supported on macOS only; use --to dotenvx on this machine.");
|
|
37380
|
+
const keytar = await loadKeytar();
|
|
37381
|
+
if (!keytar) throw new Error('the os-keychain target needs the optional native module "keytar"; reinstall morphix-env or use --to dotenvx.');
|
|
37382
|
+
const snapshot = snapshotValues(unit);
|
|
37383
|
+
for (const file of unit.files) backups.push(backupFile(file, stamp));
|
|
37384
|
+
const preExisting = new Map((await keytar.findCredentials(service)).map(({ account, password }) => [account, password]));
|
|
37385
|
+
try {
|
|
37386
|
+
for (const [key, value] of Object.entries(snapshot)) await keytar.setPassword(service, key, value);
|
|
37387
|
+
const newSource = {
|
|
37388
|
+
provider: "os-keychain",
|
|
37389
|
+
service,
|
|
37390
|
+
...unit.source.override ? { override: true } : {}
|
|
37391
|
+
};
|
|
37392
|
+
const values = await reloadViaKeychain(unit, newSource, homeDir);
|
|
37393
|
+
if (!snapshotCovered(snapshot, values)) {
|
|
37394
|
+
throw new Error("post-migration verification failed: keychain values differ from the plaintext snapshot.");
|
|
37395
|
+
}
|
|
37396
|
+
const foreign = Object.keys(values).filter((key) => !(key in snapshot));
|
|
37397
|
+
const warnings = foreign.length ? [`[morphix-env] Warning: keychain service "${service}" also holds ${foreign.length} unrelated account(s) (e.g. "${foreign[0]}"); verify the service is not shared unexpectedly.`] : [];
|
|
37398
|
+
rewriteDeclaredSource(unit, newSource, stamp, backups);
|
|
37399
|
+
for (const file of unit.files) (0, import_fs7.rmSync)(file);
|
|
37400
|
+
return { warnings };
|
|
37401
|
+
} catch (error) {
|
|
37402
|
+
const failed = restoreBackups(backups);
|
|
37403
|
+
for (const key of Object.keys(snapshot)) {
|
|
37404
|
+
if (preExisting.has(key)) {
|
|
37405
|
+
await keytar.setPassword(service, key, preExisting.get(key)).catch(() => {
|
|
37406
|
+
});
|
|
37407
|
+
} else {
|
|
37408
|
+
await keytar.deletePassword(service, key).catch(() => {
|
|
37409
|
+
});
|
|
37410
|
+
}
|
|
37411
|
+
}
|
|
37412
|
+
const message = error instanceof Error ? error.message : "unknown failure";
|
|
37413
|
+
throw new Error(withRestoreOutcome(message, failed, backups));
|
|
37414
|
+
}
|
|
37415
|
+
}
|
|
37416
|
+
async function executeUnit(unit, target, options = {}, homeDir = (0, import_os5.homedir)()) {
|
|
37417
|
+
if (unit.kind === "global-implicit" && target === "keychain") {
|
|
37418
|
+
return {
|
|
37419
|
+
unit,
|
|
37420
|
+
status: "skipped",
|
|
37421
|
+
backups: [],
|
|
37422
|
+
warnings: [],
|
|
37423
|
+
detail: "the global implicit file cannot migrate to os-keychain (its loading does not go through profiles); use --to dotenvx for it."
|
|
37424
|
+
};
|
|
37425
|
+
}
|
|
37426
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
37427
|
+
const backups = [];
|
|
37428
|
+
if (!unit.keyNames.length) {
|
|
37429
|
+
return { unit, status: "skipped", backups: [], warnings: [], detail: "no keys in the file(s); nothing to migrate." };
|
|
37430
|
+
}
|
|
37431
|
+
try {
|
|
37432
|
+
const { warnings } = target === "dotenvx" ? await migrateToDotenvx(unit, stamp, homeDir, backups) : await migrateToKeychain(unit, options.service || `mx-env:${unit.name}`, stamp, homeDir, backups);
|
|
37433
|
+
return { unit, status: "migrated", backups, warnings, detail: "" };
|
|
37434
|
+
} catch (error) {
|
|
37435
|
+
const message = error instanceof Error ? error.message : "unknown failure";
|
|
37436
|
+
return { unit, status: "failed", backups, warnings: [], detail: message };
|
|
37437
|
+
}
|
|
37438
|
+
}
|
|
37439
|
+
|
|
37157
37440
|
// src/redaction.ts
|
|
37158
37441
|
var StreamingRedactor = class {
|
|
37159
37442
|
constructor(values) {
|
|
@@ -37294,14 +37577,14 @@ var ReferenceResolver = class {
|
|
|
37294
37577
|
};
|
|
37295
37578
|
|
|
37296
37579
|
// src/skill.ts
|
|
37297
|
-
var
|
|
37298
|
-
var
|
|
37299
|
-
var
|
|
37580
|
+
var import_fs8 = require("fs");
|
|
37581
|
+
var import_os6 = require("os");
|
|
37582
|
+
var import_path8 = require("path");
|
|
37300
37583
|
var SKILL_TARGETS = ["global", "project", "trellis"];
|
|
37301
37584
|
function resolveSkillPath(target) {
|
|
37302
|
-
if (target === "project") return (0,
|
|
37303
|
-
if (target === "trellis") return (0,
|
|
37304
|
-
return (0,
|
|
37585
|
+
if (target === "project") return (0, import_path8.join)(process.cwd(), ".claude", "skills", "morphix-env", "SKILL.md");
|
|
37586
|
+
if (target === "trellis") return (0, import_path8.join)((0, import_os6.homedir)(), ".trellis", "skills", "morphix-env", "SKILL.md");
|
|
37587
|
+
return (0, import_path8.join)((0, import_os6.homedir)(), ".claude", "skills", "morphix-env", "SKILL.md");
|
|
37305
37588
|
}
|
|
37306
37589
|
function targetHint(target) {
|
|
37307
37590
|
if (target === "project") {
|
|
@@ -37320,17 +37603,17 @@ function printNextSteps() {
|
|
|
37320
37603
|
4. mx-env doc generate this project's key-to-source workflow Skill`);
|
|
37321
37604
|
}
|
|
37322
37605
|
function cmdSkill(subcommand, options) {
|
|
37323
|
-
const templatePath = (0,
|
|
37324
|
-
const template = (0,
|
|
37606
|
+
const templatePath = (0, import_path8.join)(__dirname, "SKILL.md");
|
|
37607
|
+
const template = (0, import_fs8.readFileSync)(templatePath, "utf8");
|
|
37325
37608
|
if (subcommand === "show") {
|
|
37326
37609
|
console.log(`[morphix-env] Skill template: ${templatePath}`);
|
|
37327
37610
|
for (const target2 of SKILL_TARGETS) {
|
|
37328
37611
|
const path = resolveSkillPath(target2);
|
|
37329
|
-
if (!(0,
|
|
37612
|
+
if (!(0, import_fs8.existsSync)(path)) {
|
|
37330
37613
|
console.log(` ${target2}: not installed (${path})`);
|
|
37331
37614
|
continue;
|
|
37332
37615
|
}
|
|
37333
|
-
const state = (0,
|
|
37616
|
+
const state = (0, import_fs8.readFileSync)(path, "utf8") === template ? "installed (matches this version)" : "installed (differs from this version)";
|
|
37334
37617
|
console.log(` ${target2}: ${state} (${path})`);
|
|
37335
37618
|
}
|
|
37336
37619
|
return 0;
|
|
@@ -37345,8 +37628,8 @@ function cmdSkill(subcommand, options) {
|
|
|
37345
37628
|
return 1;
|
|
37346
37629
|
}
|
|
37347
37630
|
const dest = resolveSkillPath(target);
|
|
37348
|
-
if ((0,
|
|
37349
|
-
if ((0,
|
|
37631
|
+
if ((0, import_fs8.existsSync)(dest)) {
|
|
37632
|
+
if ((0, import_fs8.readFileSync)(dest, "utf8") === template) {
|
|
37350
37633
|
console.log(`[morphix-env] Skill already installed and up to date: ${dest}`);
|
|
37351
37634
|
return 0;
|
|
37352
37635
|
}
|
|
@@ -37355,8 +37638,8 @@ function cmdSkill(subcommand, options) {
|
|
|
37355
37638
|
return 1;
|
|
37356
37639
|
}
|
|
37357
37640
|
}
|
|
37358
|
-
(0,
|
|
37359
|
-
(0,
|
|
37641
|
+
(0, import_fs8.mkdirSync)((0, import_path8.dirname)(dest), { recursive: true });
|
|
37642
|
+
(0, import_fs8.writeFileSync)(dest, template, { mode: 420 });
|
|
37360
37643
|
console.log(`[morphix-env] Installed skill: ${dest}`);
|
|
37361
37644
|
console.log(`[morphix-env] ${targetHint(target)}`);
|
|
37362
37645
|
printNextSteps();
|
|
@@ -37438,9 +37721,9 @@ async function startSecretServer(values) {
|
|
|
37438
37721
|
}
|
|
37439
37722
|
|
|
37440
37723
|
// src/shims.ts
|
|
37441
|
-
var
|
|
37442
|
-
var
|
|
37443
|
-
var
|
|
37724
|
+
var import_fs9 = require("fs");
|
|
37725
|
+
var import_os7 = require("os");
|
|
37726
|
+
var import_path9 = require("path");
|
|
37444
37727
|
var SHIM_MARKER = "# mx-env shim \u2014 regenerated by `mx-env shell-init`; do not edit by hand.";
|
|
37445
37728
|
var RESERVED_SHIM_NAMES = [
|
|
37446
37729
|
"run",
|
|
@@ -37451,6 +37734,7 @@ var RESERVED_SHIM_NAMES = [
|
|
|
37451
37734
|
"generate",
|
|
37452
37735
|
"gen",
|
|
37453
37736
|
"inspect",
|
|
37737
|
+
"migrate",
|
|
37454
37738
|
"audit",
|
|
37455
37739
|
"edit",
|
|
37456
37740
|
"doc",
|
|
@@ -37462,8 +37746,8 @@ var RESERVED_SHIM_NAMES = [
|
|
|
37462
37746
|
"__mx_editor"
|
|
37463
37747
|
];
|
|
37464
37748
|
var SHIM_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
37465
|
-
function shimsDir(homeDir = (0,
|
|
37466
|
-
return (0,
|
|
37749
|
+
function shimsDir(homeDir = (0, import_os7.homedir)()) {
|
|
37750
|
+
return (0, import_path9.join)(homeDir, ".mx-env", "shims");
|
|
37467
37751
|
}
|
|
37468
37752
|
function validateShimList(list, label) {
|
|
37469
37753
|
if (list === void 0 || list === null) return [];
|
|
@@ -37518,33 +37802,33 @@ MXENV_SHIM=1 exec mx-env run -- ${command} "$@"
|
|
|
37518
37802
|
}
|
|
37519
37803
|
function readIfExists(path) {
|
|
37520
37804
|
try {
|
|
37521
|
-
return (0,
|
|
37805
|
+
return (0, import_fs9.readFileSync)(path, "utf8");
|
|
37522
37806
|
} catch {
|
|
37523
37807
|
return null;
|
|
37524
37808
|
}
|
|
37525
37809
|
}
|
|
37526
|
-
function writeShims(commands, homeDir = (0,
|
|
37810
|
+
function writeShims(commands, homeDir = (0, import_os7.homedir)()) {
|
|
37527
37811
|
const dir = shimsDir(homeDir);
|
|
37528
|
-
(0,
|
|
37812
|
+
(0, import_fs9.mkdirSync)(dir, { recursive: true, mode: 448 });
|
|
37529
37813
|
const wanted = new Set(commands.map((command) => command.toLowerCase()));
|
|
37530
37814
|
const written = [];
|
|
37531
37815
|
const removed = [];
|
|
37532
37816
|
const skipped = [];
|
|
37533
|
-
for (const file of (0,
|
|
37534
|
-
const path = (0,
|
|
37817
|
+
for (const file of (0, import_fs9.readdirSync)(dir)) {
|
|
37818
|
+
const path = (0, import_path9.join)(dir, file);
|
|
37535
37819
|
const content = readIfExists(path);
|
|
37536
37820
|
if (content === null || !content.includes(SHIM_MARKER)) continue;
|
|
37537
37821
|
if (!wanted.has(file.toLowerCase())) {
|
|
37538
|
-
(0,
|
|
37822
|
+
(0, import_fs9.rmSync)(path);
|
|
37539
37823
|
removed.push(file);
|
|
37540
37824
|
}
|
|
37541
37825
|
}
|
|
37542
37826
|
for (const command of commands) {
|
|
37543
|
-
const path = (0,
|
|
37827
|
+
const path = (0, import_path9.join)(dir, command);
|
|
37544
37828
|
const content = renderShimScript(command);
|
|
37545
37829
|
let isSymlink = false;
|
|
37546
37830
|
try {
|
|
37547
|
-
isSymlink = (0,
|
|
37831
|
+
isSymlink = (0, import_fs9.lstatSync)(path).isSymbolicLink();
|
|
37548
37832
|
} catch {
|
|
37549
37833
|
}
|
|
37550
37834
|
const existing = isSymlink ? null : readIfExists(path);
|
|
@@ -37552,42 +37836,42 @@ function writeShims(commands, homeDir = (0, import_os6.homedir)()) {
|
|
|
37552
37836
|
skipped.push(command);
|
|
37553
37837
|
continue;
|
|
37554
37838
|
}
|
|
37555
|
-
if (isSymlink) (0,
|
|
37839
|
+
if (isSymlink) (0, import_fs9.rmSync)(path);
|
|
37556
37840
|
else if (existing === content) continue;
|
|
37557
|
-
(0,
|
|
37558
|
-
(0,
|
|
37841
|
+
(0, import_fs9.writeFileSync)(path, content, { mode: 493 });
|
|
37842
|
+
(0, import_fs9.chmodSync)(path, 493);
|
|
37559
37843
|
written.push(command);
|
|
37560
37844
|
}
|
|
37561
37845
|
return { written, removed, skipped };
|
|
37562
37846
|
}
|
|
37563
|
-
function removeAllShims(homeDir = (0,
|
|
37847
|
+
function removeAllShims(homeDir = (0, import_os7.homedir)()) {
|
|
37564
37848
|
const dir = shimsDir(homeDir);
|
|
37565
|
-
if (!(0,
|
|
37849
|
+
if (!(0, import_fs9.existsSync)(dir)) return [];
|
|
37566
37850
|
const removed = [];
|
|
37567
|
-
for (const file of (0,
|
|
37568
|
-
const path = (0,
|
|
37851
|
+
for (const file of (0, import_fs9.readdirSync)(dir)) {
|
|
37852
|
+
const path = (0, import_path9.join)(dir, file);
|
|
37569
37853
|
const content = readIfExists(path);
|
|
37570
37854
|
if (content !== null && content.includes(SHIM_MARKER)) {
|
|
37571
|
-
(0,
|
|
37855
|
+
(0, import_fs9.rmSync)(path);
|
|
37572
37856
|
removed.push(file);
|
|
37573
37857
|
}
|
|
37574
37858
|
}
|
|
37575
37859
|
return removed;
|
|
37576
37860
|
}
|
|
37577
|
-
function detectHandmadeReservedShims(homeDir = (0,
|
|
37861
|
+
function detectHandmadeReservedShims(homeDir = (0, import_os7.homedir)()) {
|
|
37578
37862
|
const dir = shimsDir(homeDir);
|
|
37579
|
-
if (!(0,
|
|
37863
|
+
if (!(0, import_fs9.existsSync)(dir)) return [];
|
|
37580
37864
|
const found = [];
|
|
37581
|
-
for (const file of (0,
|
|
37865
|
+
for (const file of (0, import_fs9.readdirSync)(dir)) {
|
|
37582
37866
|
if (!RESERVED_SHIM_NAMES.includes(file.toLowerCase())) continue;
|
|
37583
|
-
const content = readIfExists((0,
|
|
37867
|
+
const content = readIfExists((0, import_path9.join)(dir, file));
|
|
37584
37868
|
if (content === null || !content.includes(SHIM_MARKER)) found.push(file);
|
|
37585
37869
|
}
|
|
37586
37870
|
return found;
|
|
37587
37871
|
}
|
|
37588
37872
|
var RC_BLOCK_BEGIN = "# >>> mx-env shims >>>";
|
|
37589
37873
|
var RC_BLOCK_END = "# <<< mx-env shims <<<";
|
|
37590
|
-
function rcBlock(homeDir = (0,
|
|
37874
|
+
function rcBlock(homeDir = (0, import_os7.homedir)()) {
|
|
37591
37875
|
const dir = shimsDir(homeDir);
|
|
37592
37876
|
if (/["$`\\]/.test(dir)) {
|
|
37593
37877
|
throw new Error("[morphix-env] Shims directory path contains characters that are unsafe in a shell rc line.");
|
|
@@ -37596,18 +37880,18 @@ function rcBlock(homeDir = (0, import_os6.homedir)()) {
|
|
|
37596
37880
|
export PATH="${dir}:$PATH"
|
|
37597
37881
|
${RC_BLOCK_END}`;
|
|
37598
37882
|
}
|
|
37599
|
-
function defaultRcPath(shell, homeDir = (0,
|
|
37883
|
+
function defaultRcPath(shell, homeDir = (0, import_os7.homedir)()) {
|
|
37600
37884
|
const name = shell ? shell.split("/").pop() : "";
|
|
37601
|
-
if (name === "zsh") return (0,
|
|
37602
|
-
if (name === "bash") return (0,
|
|
37885
|
+
if (name === "zsh") return (0, import_path9.join)(homeDir, ".zshrc");
|
|
37886
|
+
if (name === "bash") return (0, import_path9.join)(homeDir, ".bashrc");
|
|
37603
37887
|
return null;
|
|
37604
37888
|
}
|
|
37605
37889
|
function writeFileAtomic(path, content) {
|
|
37606
37890
|
const tmp = `${path}.mx-env-${process.pid}.tmp`;
|
|
37607
|
-
(0,
|
|
37608
|
-
(0,
|
|
37891
|
+
(0, import_fs9.writeFileSync)(tmp, content);
|
|
37892
|
+
(0, import_fs9.renameSync)(tmp, path);
|
|
37609
37893
|
}
|
|
37610
|
-
function upsertRcBlock(rcPath, homeDir = (0,
|
|
37894
|
+
function upsertRcBlock(rcPath, homeDir = (0, import_os7.homedir)()) {
|
|
37611
37895
|
const existing = readIfExists(rcPath) ?? "";
|
|
37612
37896
|
const block = rcBlock(homeDir);
|
|
37613
37897
|
const pattern = new RegExp(`${escapeRegExp(RC_BLOCK_BEGIN)}[\\s\\S]*?${escapeRegExp(RC_BLOCK_END)}`, "g");
|
|
@@ -37634,32 +37918,32 @@ function removeRcBlock(rcPath) {
|
|
|
37634
37918
|
function escapeRegExp(text) {
|
|
37635
37919
|
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
37636
37920
|
}
|
|
37637
|
-
function stripShimsFromPath(pathValue, homeDir = (0,
|
|
37921
|
+
function stripShimsFromPath(pathValue, homeDir = (0, import_os7.homedir)()) {
|
|
37638
37922
|
if (!pathValue) return pathValue;
|
|
37639
37923
|
const target = shimsDir(homeDir);
|
|
37640
37924
|
let targetReal = target;
|
|
37641
37925
|
try {
|
|
37642
|
-
targetReal = (0,
|
|
37926
|
+
targetReal = (0, import_fs9.realpathSync)(target);
|
|
37643
37927
|
} catch {
|
|
37644
37928
|
}
|
|
37645
37929
|
const equal = (a, b) => process.platform === "darwin" ? a.toLowerCase() === b.toLowerCase() : a === b;
|
|
37646
|
-
const entries = pathValue.split(
|
|
37930
|
+
const entries = pathValue.split(import_path9.delimiter).filter((entry) => {
|
|
37647
37931
|
if (!entry) return true;
|
|
37648
37932
|
const literal = entry.replace(/\/+$/, "");
|
|
37649
37933
|
let resolved = literal;
|
|
37650
37934
|
try {
|
|
37651
|
-
resolved = (0,
|
|
37935
|
+
resolved = (0, import_fs9.realpathSync)(literal);
|
|
37652
37936
|
} catch {
|
|
37653
37937
|
}
|
|
37654
37938
|
return !equal(literal, target) && !equal(resolved, targetReal);
|
|
37655
37939
|
});
|
|
37656
|
-
return entries.join(
|
|
37940
|
+
return entries.join(import_path9.delimiter);
|
|
37657
37941
|
}
|
|
37658
37942
|
function sanitizeBootEnv(env = process.env, homeDir) {
|
|
37659
37943
|
const originalPath = env.PATH;
|
|
37660
37944
|
const viaShim = env.MXENV_SHIM === "1";
|
|
37661
37945
|
try {
|
|
37662
|
-
const home = homeDir ?? (0,
|
|
37946
|
+
const home = homeDir ?? (0, import_os7.homedir)();
|
|
37663
37947
|
const stripped = stripShimsFromPath(originalPath, home);
|
|
37664
37948
|
if (stripped !== originalPath) {
|
|
37665
37949
|
if (stripped) env.PATH = stripped;
|
|
@@ -37670,18 +37954,18 @@ function sanitizeBootEnv(env = process.env, homeDir) {
|
|
|
37670
37954
|
delete env.MXENV_SHIM;
|
|
37671
37955
|
return { viaShim, originalPath };
|
|
37672
37956
|
}
|
|
37673
|
-
function findShadowedCommands(commands, originalPath, homeDir = (0,
|
|
37957
|
+
function findShadowedCommands(commands, originalPath, homeDir = (0, import_os7.homedir)()) {
|
|
37674
37958
|
if (!originalPath) return { absent: [...commands], shadowed: [] };
|
|
37675
|
-
const dirs = originalPath.split(
|
|
37959
|
+
const dirs = originalPath.split(import_path9.delimiter).filter(Boolean);
|
|
37676
37960
|
const absent = [];
|
|
37677
37961
|
const shadowed = [];
|
|
37678
37962
|
for (const command of commands) {
|
|
37679
|
-
const shimPath = (0,
|
|
37963
|
+
const shimPath = (0, import_path9.join)(shimsDir(homeDir), command);
|
|
37680
37964
|
let resolvedTo = null;
|
|
37681
37965
|
for (const dir of dirs) {
|
|
37682
|
-
const candidate = (0,
|
|
37966
|
+
const candidate = (0, import_path9.join)(dir, command);
|
|
37683
37967
|
try {
|
|
37684
|
-
(0,
|
|
37968
|
+
(0, import_fs9.accessSync)(candidate, import_fs9.constants.X_OK);
|
|
37685
37969
|
resolvedTo = candidate;
|
|
37686
37970
|
break;
|
|
37687
37971
|
} catch {
|
|
@@ -37695,9 +37979,9 @@ function findShadowedCommands(commands, originalPath, homeDir = (0, import_os6.h
|
|
|
37695
37979
|
}
|
|
37696
37980
|
|
|
37697
37981
|
// src/template.ts
|
|
37698
|
-
var
|
|
37699
|
-
var
|
|
37700
|
-
var
|
|
37982
|
+
var import_child_process5 = require("child_process");
|
|
37983
|
+
var import_fs10 = require("fs");
|
|
37984
|
+
var import_path10 = require("path");
|
|
37701
37985
|
function shellQuote(value) {
|
|
37702
37986
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
37703
37987
|
}
|
|
@@ -37744,20 +38028,20 @@ function renderTemplate(text, environment) {
|
|
|
37744
38028
|
return { output, missing: [...missing] };
|
|
37745
38029
|
}
|
|
37746
38030
|
function writePrivateFile(path, content) {
|
|
37747
|
-
const absolute = (0,
|
|
37748
|
-
(0,
|
|
37749
|
-
(0,
|
|
37750
|
-
(0,
|
|
38031
|
+
const absolute = (0, import_path10.resolve)(path);
|
|
38032
|
+
(0, import_fs10.mkdirSync)((0, import_path10.dirname)(absolute), { recursive: true, mode: 448 });
|
|
38033
|
+
(0, import_fs10.writeFileSync)(absolute, content, { mode: 384 });
|
|
38034
|
+
(0, import_fs10.chmodSync)(absolute, 384);
|
|
37751
38035
|
}
|
|
37752
38036
|
function gitOutputStatus(path) {
|
|
37753
|
-
const absolute = (0,
|
|
37754
|
-
const cwd = (0,
|
|
37755
|
-
const name = (0,
|
|
37756
|
-
const inside = (0,
|
|
38037
|
+
const absolute = (0, import_path10.resolve)(path);
|
|
38038
|
+
const cwd = (0, import_path10.dirname)(absolute);
|
|
38039
|
+
const name = (0, import_path10.basename)(absolute);
|
|
38040
|
+
const inside = (0, import_child_process5.spawnSync)("git", ["rev-parse", "--is-inside-work-tree"], { cwd, encoding: "utf8" });
|
|
37757
38041
|
if (inside.status !== 0) return "outside-repo";
|
|
37758
|
-
const tracked = (0,
|
|
38042
|
+
const tracked = (0, import_child_process5.spawnSync)("git", ["ls-files", "--error-unmatch", "--", name], { cwd, encoding: "utf8" });
|
|
37759
38043
|
if (tracked.status === 0) return "tracked";
|
|
37760
|
-
const ignored = (0,
|
|
38044
|
+
const ignored = (0, import_child_process5.spawnSync)("git", ["check-ignore", "-q", "--", name], { cwd, encoding: "utf8" });
|
|
37761
38045
|
if (ignored.status === 0) return "ignored";
|
|
37762
38046
|
if (ignored.status === 1) return "untracked";
|
|
37763
38047
|
return "outside-repo";
|
|
@@ -37774,7 +38058,7 @@ function warnOutputGitRisk(path) {
|
|
|
37774
38058
|
// package.json
|
|
37775
38059
|
var package_default = {
|
|
37776
38060
|
name: "morphix-env",
|
|
37777
|
-
version: "0.
|
|
38061
|
+
version: "0.10.0",
|
|
37778
38062
|
description: "Secret composition CLI \u2014 Infisical, Doppler, macOS Keychain, dotenvx, and local files stay value owners; composes them into one value-safe child environment and ships a built-in Agent Skill (mx-env skill install).",
|
|
37779
38063
|
author: "MorphixAI <dev@morphixai.com>",
|
|
37780
38064
|
homepage: "https://github.com/Morphicai/morphix-env#readme",
|
|
@@ -37879,11 +38163,14 @@ function parseArgs(argv) {
|
|
|
37879
38163
|
printEditorUrl: false,
|
|
37880
38164
|
source: null,
|
|
37881
38165
|
target: null,
|
|
38166
|
+
to: null,
|
|
38167
|
+
service: null,
|
|
37882
38168
|
force: false,
|
|
37883
38169
|
dryRun: false,
|
|
37884
38170
|
serve: false,
|
|
37885
38171
|
write: false,
|
|
37886
38172
|
remove: false,
|
|
38173
|
+
warnPlaintext: false,
|
|
37887
38174
|
unknownFlags: []
|
|
37888
38175
|
};
|
|
37889
38176
|
let i = 2;
|
|
@@ -37921,6 +38208,10 @@ function parseArgs(argv) {
|
|
|
37921
38208
|
args.printEditorUrl = true;
|
|
37922
38209
|
} else if (arg === "--target") {
|
|
37923
38210
|
if (argv[++i]) args.target = argv[i];
|
|
38211
|
+
} else if (arg === "--to") {
|
|
38212
|
+
if (argv[++i]) args.to = argv[i];
|
|
38213
|
+
} else if (arg === "--service") {
|
|
38214
|
+
if (argv[++i]) args.service = argv[i];
|
|
37924
38215
|
} else if (arg === "--force") {
|
|
37925
38216
|
args.force = true;
|
|
37926
38217
|
} else if (arg === "--dry-run") {
|
|
@@ -37931,6 +38222,8 @@ function parseArgs(argv) {
|
|
|
37931
38222
|
args.remove = true;
|
|
37932
38223
|
} else if (arg === "--serve") {
|
|
37933
38224
|
args.serve = true;
|
|
38225
|
+
} else if (arg === "--warn-plaintext") {
|
|
38226
|
+
args.warnPlaintext = true;
|
|
37934
38227
|
} else if (args.command === "run") {
|
|
37935
38228
|
args.subArgs = argv.slice(i);
|
|
37936
38229
|
break;
|
|
@@ -37944,7 +38237,7 @@ function parseArgs(argv) {
|
|
|
37944
38237
|
return args;
|
|
37945
38238
|
}
|
|
37946
38239
|
function configLayers() {
|
|
37947
|
-
return loadConfigLayers({ cwd: process.cwd(), homeDir: (0,
|
|
38240
|
+
return loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os8.homedir)() });
|
|
37948
38241
|
}
|
|
37949
38242
|
function composeOptions(args) {
|
|
37950
38243
|
return {
|
|
@@ -37954,7 +38247,7 @@ function composeOptions(args) {
|
|
|
37954
38247
|
envName: args.env,
|
|
37955
38248
|
allowInsecureGlobal: args.allowInsecureGlobal,
|
|
37956
38249
|
envFiles: args.envFiles,
|
|
37957
|
-
homeDir: (0,
|
|
38250
|
+
homeDir: (0, import_os8.homedir)()
|
|
37958
38251
|
};
|
|
37959
38252
|
}
|
|
37960
38253
|
var bootInfo = { viaShim: false };
|
|
@@ -37975,8 +38268,19 @@ function resolveComposition(args) {
|
|
|
37975
38268
|
warnInvalidShims(layers, !args.noGlobal);
|
|
37976
38269
|
return composeEnvironment(layers, composeOptions(args));
|
|
37977
38270
|
}
|
|
38271
|
+
var plaintextWarned = false;
|
|
38272
|
+
function warnPlaintextSources(composition, args) {
|
|
38273
|
+
if (plaintextWarned) return;
|
|
38274
|
+
if (!args.warnPlaintext && process.env.MXENV_WARN_PLAINTEXT !== "1") return;
|
|
38275
|
+
plaintextWarned = true;
|
|
38276
|
+
const loaded = composition.sourceStatuses.filter(
|
|
38277
|
+
(source) => source.provider === "local" && source.availability === "loaded" && source.keyCount > 0
|
|
38278
|
+
);
|
|
38279
|
+
if (!loaded.length) return;
|
|
38280
|
+
console.warn(`[morphix-env] Plaintext local source(s) in use: ${loaded.map((source) => source.name).join(", ")} \u2014 local plaintext files are dev-only; run \`mx-env migrate\` to move them into encrypted storage.`);
|
|
38281
|
+
}
|
|
37978
38282
|
function generatedOptions(args) {
|
|
37979
|
-
const config = loadConfigLayers({ cwd: process.cwd(), homeDir: (0,
|
|
38283
|
+
const config = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os8.homedir)() }).project.config;
|
|
37980
38284
|
return {
|
|
37981
38285
|
outFile: args.outFile || config.generate?.out || "public/__env.js",
|
|
37982
38286
|
filter: args.filter || config.generate?.filter || null
|
|
@@ -37985,12 +38289,12 @@ function generatedOptions(args) {
|
|
|
37985
38289
|
function generateClientEnv(outFile, filter, environment) {
|
|
37986
38290
|
let vars = extractPublicVars(environment);
|
|
37987
38291
|
if (filter) vars = Object.fromEntries(Object.entries(vars).filter(([key]) => key.startsWith(filter)));
|
|
37988
|
-
(0,
|
|
37989
|
-
(0,
|
|
38292
|
+
(0, import_fs11.mkdirSync)((0, import_path11.dirname)(outFile), { recursive: true });
|
|
38293
|
+
(0, import_fs11.writeFileSync)(outFile, `window.__ENV=${JSON.stringify(vars)};`);
|
|
37990
38294
|
console.log(`[morphix-env] Generated ${outFile} (${Object.keys(vars).length} client vars)`);
|
|
37991
38295
|
}
|
|
37992
38296
|
async function runChild(command, commandArgs, composition) {
|
|
37993
|
-
return new Promise((
|
|
38297
|
+
return new Promise((resolve8) => {
|
|
37994
38298
|
if (composition.environment.PATH) {
|
|
37995
38299
|
composition.environment.PATH = stripShimsFromPath(composition.environment.PATH) ?? composition.environment.PATH;
|
|
37996
38300
|
}
|
|
@@ -38001,14 +38305,14 @@ async function runChild(command, commandArgs, composition) {
|
|
|
38001
38305
|
child.stderr?.on("data", (chunk) => process.stderr.write(stderr.write(chunk)));
|
|
38002
38306
|
child.on("error", () => {
|
|
38003
38307
|
console.error(`[morphix-env] Failed to execute: ${command}`);
|
|
38004
|
-
|
|
38308
|
+
resolve8(1);
|
|
38005
38309
|
});
|
|
38006
38310
|
child.on("close", (code) => {
|
|
38007
38311
|
const stdoutFinal = stdout.flush();
|
|
38008
38312
|
const stderrFinal = stderr.flush();
|
|
38009
38313
|
if (stdoutFinal) process.stdout.write(stdoutFinal);
|
|
38010
38314
|
if (stderrFinal) process.stderr.write(stderrFinal);
|
|
38011
|
-
|
|
38315
|
+
resolve8(code ?? 1);
|
|
38012
38316
|
});
|
|
38013
38317
|
});
|
|
38014
38318
|
}
|
|
@@ -38074,6 +38378,7 @@ async function cmdRun(args) {
|
|
|
38074
38378
|
}
|
|
38075
38379
|
const startedAt = Date.now();
|
|
38076
38380
|
const composition = await resolveComposition(args);
|
|
38381
|
+
warnPlaintextSources(composition, args);
|
|
38077
38382
|
if (args.verbose) {
|
|
38078
38383
|
for (const source of composition.sourceStatuses) {
|
|
38079
38384
|
console.log(`[morphix-env] ${source.name}: ${source.availability} (${source.keyCount} keys)`);
|
|
@@ -38087,7 +38392,7 @@ async function cmdRun(args) {
|
|
|
38087
38392
|
await resolveEnvironmentReferences(composition, args);
|
|
38088
38393
|
if (args.outFile || generatedOptions(args).outFile) {
|
|
38089
38394
|
const { outFile, filter } = generatedOptions(args);
|
|
38090
|
-
const configured = Boolean(args.outFile || loadConfigLayers({ cwd: process.cwd(), homeDir: (0,
|
|
38395
|
+
const configured = Boolean(args.outFile || loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os8.homedir)() }).project.config.generate);
|
|
38091
38396
|
if (configured) generateClientEnv(outFile, filter, composition.environment);
|
|
38092
38397
|
}
|
|
38093
38398
|
const [command, ...commandArgs] = args.subArgs;
|
|
@@ -38144,6 +38449,7 @@ async function cmdFetch(args) {
|
|
|
38144
38449
|
}
|
|
38145
38450
|
async function cmdGenerate(args) {
|
|
38146
38451
|
const composition = await resolveComposition(args);
|
|
38452
|
+
warnPlaintextSources(composition, args);
|
|
38147
38453
|
await resolveEnvironmentReferences(composition, args);
|
|
38148
38454
|
const { outFile, filter } = generatedOptions(args);
|
|
38149
38455
|
generateClientEnv(outFile, filter, composition.environment);
|
|
@@ -38156,7 +38462,8 @@ async function cmdInspect(args) {
|
|
|
38156
38462
|
const composition = await resolveComposition(args);
|
|
38157
38463
|
console.log(`profile: ${composition.profileName}`);
|
|
38158
38464
|
for (const source of composition.sourceStatuses) {
|
|
38159
|
-
|
|
38465
|
+
const plaintextMark = source.provider === "local" ? " [plaintext, dev-only]" : "";
|
|
38466
|
+
console.log(`source: ${source.name} (${source.provider}) \u2014 ${source.availability}, ${source.keyCount} keys${plaintextMark}`);
|
|
38160
38467
|
}
|
|
38161
38468
|
for (const [key, provenance] of Object.entries(composition.provenance).sort(([a], [b]) => a.localeCompare(b))) {
|
|
38162
38469
|
if (!args.filter || key.startsWith(args.filter)) {
|
|
@@ -38169,6 +38476,7 @@ async function cmdInspect(args) {
|
|
|
38169
38476
|
async function cmdExport(args) {
|
|
38170
38477
|
const startedAt = Date.now();
|
|
38171
38478
|
const composition = await resolveComposition(args);
|
|
38479
|
+
warnPlaintextSources(composition, args);
|
|
38172
38480
|
const keys = Object.keys(composition.provenance).sort();
|
|
38173
38481
|
if (args.dryRun) {
|
|
38174
38482
|
for (const key of keys) console.log(key);
|
|
@@ -38192,12 +38500,13 @@ async function cmdRender(args) {
|
|
|
38192
38500
|
console.error("[morphix-env] Usage: mx-env render <template-file> <output-file> [options]");
|
|
38193
38501
|
return 1;
|
|
38194
38502
|
}
|
|
38195
|
-
if (!(0,
|
|
38503
|
+
if (!(0, import_fs11.existsSync)(templatePath)) {
|
|
38196
38504
|
console.error(`[morphix-env] Template not found: ${templatePath}`);
|
|
38197
38505
|
return 1;
|
|
38198
38506
|
}
|
|
38199
|
-
const template = (0,
|
|
38507
|
+
const template = (0, import_fs11.readFileSync)(templatePath, "utf8");
|
|
38200
38508
|
const composition = await resolveComposition(args);
|
|
38509
|
+
warnPlaintextSources(composition, args);
|
|
38201
38510
|
const names = findTemplateVariables(template);
|
|
38202
38511
|
const missing = names.filter((name) => composition.environment[name] === void 0 || composition.environment[name] === null);
|
|
38203
38512
|
if (missing.length) console.warn(`[morphix-env] Missing variables: ${missing.join(", ")} (left unresolved)`);
|
|
@@ -38221,11 +38530,11 @@ async function cmdInject(args) {
|
|
|
38221
38530
|
console.error("[morphix-env] Usage: mx-env inject <template-file> <output-file> [options]");
|
|
38222
38531
|
return 1;
|
|
38223
38532
|
}
|
|
38224
|
-
if (!(0,
|
|
38533
|
+
if (!(0, import_fs11.existsSync)(templatePath)) {
|
|
38225
38534
|
console.error(`[morphix-env] Template not found: ${templatePath}`);
|
|
38226
38535
|
return 1;
|
|
38227
38536
|
}
|
|
38228
|
-
const template = (0,
|
|
38537
|
+
const template = (0, import_fs11.readFileSync)(templatePath, "utf8");
|
|
38229
38538
|
const layers = configLayers();
|
|
38230
38539
|
warnInvalidShims(layers, !args.noGlobal);
|
|
38231
38540
|
const resolver = new ReferenceResolver(layers, composeOptions(args));
|
|
@@ -38261,7 +38570,7 @@ async function cmdEdit(args) {
|
|
|
38261
38570
|
}
|
|
38262
38571
|
const composition = await resolveComposition(args);
|
|
38263
38572
|
if (args.source && !composition.sourceEntries.some((entry) => entry.name === args.source)) {
|
|
38264
|
-
const layers = loadConfigLayers({ cwd: process.cwd(), homeDir: (0,
|
|
38573
|
+
const layers = loadConfigLayers({ cwd: process.cwd(), homeDir: (0, import_os8.homedir)() });
|
|
38265
38574
|
const declared = layers.project.config.sources?.[args.source] ? { source: layers.project.config.sources[args.source], baseDir: layers.project.baseDir } : !args.noGlobal && layers.global.config.sources?.[args.source] ? { source: layers.global.config.sources[args.source], baseDir: layers.global.baseDir } : null;
|
|
38266
38575
|
if (!declared) {
|
|
38267
38576
|
console.error(`[morphix-env] Unknown source "${args.source}".`);
|
|
@@ -38279,7 +38588,7 @@ async function cmdEdit(args) {
|
|
|
38279
38588
|
}
|
|
38280
38589
|
async function cmdDoc(args) {
|
|
38281
38590
|
const composition = await resolveComposition(args);
|
|
38282
|
-
const outFile = args.outFile || (0,
|
|
38591
|
+
const outFile = args.outFile || (0, import_path11.join)(process.cwd(), ".agents", "skills", "morphix-env", "SKILL.md");
|
|
38283
38592
|
const keyRows = Object.entries(composition.provenance).sort(([a], [b]) => a.localeCompare(b)).map(([key, provenance]) => `| \`${key}\` | ${provenance.source} (${provenance.provider}) |`).join("\n") || "| _No resolved keys_ | \u2014 |";
|
|
38284
38593
|
const skill = `---
|
|
38285
38594
|
name: morphix-env
|
|
@@ -38313,8 +38622,8 @@ ${keyRows}
|
|
|
38313
38622
|
|
|
38314
38623
|
Secret values and value prefixes do not belong in this Skill, command output, audit records, or conversation context.
|
|
38315
38624
|
`;
|
|
38316
|
-
(0,
|
|
38317
|
-
(0,
|
|
38625
|
+
(0, import_fs11.mkdirSync)((0, import_path11.dirname)(outFile), { recursive: true });
|
|
38626
|
+
(0, import_fs11.writeFileSync)(outFile, skill, { mode: 384 });
|
|
38318
38627
|
console.log(`[morphix-env] Generated value-free workflow Skill: ${outFile}`);
|
|
38319
38628
|
return 0;
|
|
38320
38629
|
}
|
|
@@ -38341,7 +38650,7 @@ function cmdShellInit(args) {
|
|
|
38341
38650
|
}
|
|
38342
38651
|
function runShellInit(args) {
|
|
38343
38652
|
const layers = configLayers();
|
|
38344
|
-
const home = (0,
|
|
38653
|
+
const home = (0, import_os8.homedir)();
|
|
38345
38654
|
const rcPath = defaultRcPath(process.env.SHELL, home);
|
|
38346
38655
|
if (args.remove) {
|
|
38347
38656
|
const removed2 = removeAllShims(home);
|
|
@@ -38390,13 +38699,117 @@ Add the shims directory to PATH${rcPath ? ` (e.g. in ${rcPath})` : ""}:
|
|
|
38390
38699
|
Or re-run with --write to let mx-env maintain a marked block in your rc file.`);
|
|
38391
38700
|
return 0;
|
|
38392
38701
|
}
|
|
38702
|
+
function printMigratePlan(units, hints, target) {
|
|
38703
|
+
if (!units.length) {
|
|
38704
|
+
console.log("[morphix-env] No plaintext units in scope; nothing to migrate.");
|
|
38705
|
+
}
|
|
38706
|
+
for (const unit of units) {
|
|
38707
|
+
const where = unit.kind === "global-implicit" ? "global implicit" : `${unit.scope}, declared in ${unit.configPath}`;
|
|
38708
|
+
console.log(`unit: ${unit.name} (${where})`);
|
|
38709
|
+
for (const file of unit.files) console.log(` file: ${file}`);
|
|
38710
|
+
console.log(` keys: ${unit.keyNames.join(", ") || "(none)"}`);
|
|
38711
|
+
console.log(` --to dotenvx: encrypt file(s) in place${unit.kind === "declared" ? " + rewrite provider in config" : " (no config change; loading auto-detects encryption)"}`);
|
|
38712
|
+
console.log(unit.kind === "global-implicit" ? " --to keychain: not supported for the global implicit file" : " --to keychain: move values to a keychain service, rewrite config, delete plaintext");
|
|
38713
|
+
}
|
|
38714
|
+
for (const hint of hints) {
|
|
38715
|
+
console.log(`legacy plaintext (not auto-migrated): ${hint} \u2014 declare it as a source in mx-env.config.json to migrate it.`);
|
|
38716
|
+
}
|
|
38717
|
+
if (units.length && !target) {
|
|
38718
|
+
console.log("\nPlan only. Re-run with --to dotenvx|keychain to execute; every unit gets a 0600 backup and a post-migration equivalence check before its config changes.");
|
|
38719
|
+
}
|
|
38720
|
+
}
|
|
38721
|
+
async function cmdMigrate(args) {
|
|
38722
|
+
if (args.unknownFlags.length) {
|
|
38723
|
+
console.error(`[morphix-env] migrate: unrecognized flag(s): ${args.unknownFlags.join(", ")}`);
|
|
38724
|
+
return 1;
|
|
38725
|
+
}
|
|
38726
|
+
if (args.to && args.to !== "dotenvx" && args.to !== "keychain") {
|
|
38727
|
+
console.error('[morphix-env] migrate: --to must be "dotenvx" or "keychain".');
|
|
38728
|
+
return 1;
|
|
38729
|
+
}
|
|
38730
|
+
if (args.service && args.to !== "keychain") {
|
|
38731
|
+
console.error("[morphix-env] migrate: --service is only valid with --to keychain.");
|
|
38732
|
+
return 1;
|
|
38733
|
+
}
|
|
38734
|
+
if (args.service && !args.source) {
|
|
38735
|
+
console.error("[morphix-env] migrate: --service requires --source (one service per migrated source).");
|
|
38736
|
+
return 1;
|
|
38737
|
+
}
|
|
38738
|
+
const layers = configLayers();
|
|
38739
|
+
const home = (0, import_os8.homedir)();
|
|
38740
|
+
const units = discoverPlaintextUnits(layers, home);
|
|
38741
|
+
const hints = legacyPlaintextHints(layers, units, home);
|
|
38742
|
+
const fileOwners = /* @__PURE__ */ new Map();
|
|
38743
|
+
const collisions = [];
|
|
38744
|
+
for (const unit of units) {
|
|
38745
|
+
for (const file of unit.files) {
|
|
38746
|
+
const owner = fileOwners.get(file);
|
|
38747
|
+
if (owner && owner !== unit.name) {
|
|
38748
|
+
collisions.push(`file ${file} is shared by units "${owner}" and "${unit.name}"`);
|
|
38749
|
+
}
|
|
38750
|
+
if (!owner) fileOwners.set(file, unit.name);
|
|
38751
|
+
}
|
|
38752
|
+
}
|
|
38753
|
+
for (const collision of collisions) {
|
|
38754
|
+
if (!args.to || args.dryRun) console.warn(`[morphix-env] Warning: ${collision}; split them into separate files (or sources) before migrating.`);
|
|
38755
|
+
else {
|
|
38756
|
+
console.error(`[morphix-env] migrate: ${collision}; split them into separate files (or sources) before migrating.`);
|
|
38757
|
+
return 1;
|
|
38758
|
+
}
|
|
38759
|
+
}
|
|
38760
|
+
const selected = args.source ? units.filter((unit) => unit.name === args.source) : units;
|
|
38761
|
+
if (args.source && !selected.length) {
|
|
38762
|
+
console.error(`[morphix-env] migrate: no plaintext unit named "${args.source}" in scope (already migrated or unknown).`);
|
|
38763
|
+
return 1;
|
|
38764
|
+
}
|
|
38765
|
+
if (!args.to || args.dryRun) {
|
|
38766
|
+
printMigratePlan(selected, hints, args.to);
|
|
38767
|
+
return 0;
|
|
38768
|
+
}
|
|
38769
|
+
if (!selected.length) {
|
|
38770
|
+
console.log("[morphix-env] No plaintext units in scope; nothing to migrate.");
|
|
38771
|
+
return 0;
|
|
38772
|
+
}
|
|
38773
|
+
const target = args.to;
|
|
38774
|
+
const startedAt = Date.now();
|
|
38775
|
+
const outcomes = [];
|
|
38776
|
+
for (const unit of selected) {
|
|
38777
|
+
const outcome = await executeUnit(unit, target, { service: args.service || void 0 }, home);
|
|
38778
|
+
outcomes.push(outcome);
|
|
38779
|
+
if (outcome.status === "migrated") {
|
|
38780
|
+
console.log(`[morphix-env] Migrated ${unit.name} -> ${target} (${unit.keyNames.length} keys).`);
|
|
38781
|
+
for (const warning of outcome.warnings) console.warn(warning);
|
|
38782
|
+
for (const backup of outcome.backups) console.log(`[morphix-env] Backup (0600): ${backup}`);
|
|
38783
|
+
} else if (outcome.status === "skipped") {
|
|
38784
|
+
console.warn(`[morphix-env] Skipped ${unit.name}: ${outcome.detail}`);
|
|
38785
|
+
} else {
|
|
38786
|
+
console.error(`[morphix-env] Failed ${unit.name}: ${outcome.detail}`);
|
|
38787
|
+
for (const backup of outcome.backups) console.error(`[morphix-env] Backup retained (0600): ${backup} \u2014 delete it by hand once verified.`);
|
|
38788
|
+
}
|
|
38789
|
+
}
|
|
38790
|
+
const failed = outcomes.filter((outcome) => outcome.status === "failed");
|
|
38791
|
+
const exitCode = failed.length ? 1 : 0;
|
|
38792
|
+
writeAudit({
|
|
38793
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
38794
|
+
profile: "migrate",
|
|
38795
|
+
sources: selected.map((unit) => unit.name),
|
|
38796
|
+
keys: [...new Set(selected.flatMap((unit) => unit.keyNames))].sort(),
|
|
38797
|
+
outcome: failed.length ? "failure" : "success",
|
|
38798
|
+
exitCode,
|
|
38799
|
+
durationMs: Date.now() - startedAt
|
|
38800
|
+
});
|
|
38801
|
+
if (outcomes.some((outcome) => outcome.backups.length)) {
|
|
38802
|
+
console.log("[morphix-env] Backups are 0600 copies of the original plaintext \u2014 delete them once your workflows are verified.");
|
|
38803
|
+
}
|
|
38804
|
+
return exitCode;
|
|
38805
|
+
}
|
|
38393
38806
|
function cmdAudit(args) {
|
|
38394
|
-
const file = (0,
|
|
38395
|
-
if (!(0,
|
|
38807
|
+
const file = (0, import_path11.join)((0, import_os8.homedir)(), ".mx-env", "audit", `${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.jsonl`);
|
|
38808
|
+
if (!(0, import_fs11.existsSync)(file)) {
|
|
38396
38809
|
console.log("[morphix-env] No audit events for today.");
|
|
38397
38810
|
return 0;
|
|
38398
38811
|
}
|
|
38399
|
-
const lines = (0,
|
|
38812
|
+
const lines = (0, import_fs11.readFileSync)(file, "utf8").trim().split("\n").filter(Boolean);
|
|
38400
38813
|
const selected = args.subArgs[0] === "tail" ? lines.slice(-20) : lines;
|
|
38401
38814
|
for (const line of selected) console.log(line);
|
|
38402
38815
|
return 0;
|
|
@@ -38413,6 +38826,7 @@ Usage:
|
|
|
38413
38826
|
mx-env inject <template> <output> Resolve mx-env:// references into a file (mode 0600)
|
|
38414
38827
|
mx-env generate [options] Generate public __env.js
|
|
38415
38828
|
mx-env inspect [options] Print key names, sources, and status only
|
|
38829
|
+
mx-env migrate [--to dotenvx|keychain] Move plaintext local sources into encrypted storage
|
|
38416
38830
|
mx-env doc [options] Generate a value-free project Skill
|
|
38417
38831
|
mx-env audit [tail] Read value-free local audit events
|
|
38418
38832
|
mx-env edit --profile <name> Open the one-shot visual editor
|
|
@@ -38433,8 +38847,12 @@ Options:
|
|
|
38433
38847
|
--no-infisical Do not load Infisical sources
|
|
38434
38848
|
--no-global Ignore ~/.mx-env/.env and ~/.mx-env/config.json
|
|
38435
38849
|
--allow-insecure-global Allow a global .env with permissive file mode
|
|
38850
|
+
--warn-plaintext Warn once on stderr when plaintext local sources supply keys
|
|
38436
38851
|
--print-editor-url Explicitly print the one-time local editor URL
|
|
38437
38852
|
--target <scope> Skill install target: global, project, or trellis
|
|
38853
|
+
--to <provider> migrate destination: dotenvx or keychain (omit for a read-only plan)
|
|
38854
|
+
--source <name> edit/migrate: select a single source
|
|
38855
|
+
--service <name> migrate --to keychain: keychain service override (requires --source)
|
|
38438
38856
|
--force Overwrite an installed skill that differs from this version
|
|
38439
38857
|
-v, --verbose Print source status and key counts only
|
|
38440
38858
|
--help, -h Show this help
|
|
@@ -38460,6 +38878,8 @@ async function main() {
|
|
|
38460
38878
|
return cmdGenerate(args);
|
|
38461
38879
|
case "inspect":
|
|
38462
38880
|
return cmdInspect(args);
|
|
38881
|
+
case "migrate":
|
|
38882
|
+
return cmdMigrate(args);
|
|
38463
38883
|
case "audit":
|
|
38464
38884
|
return cmdAudit(args);
|
|
38465
38885
|
case "edit":
|