@rubytech/create-maxy-code 0.1.308 → 0.1.309
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/claude-ptys-slice.test.js +1 -1
- package/dist/__tests__/cloudflared-slice.test.js +1 -1
- package/dist/__tests__/macos-darwin-branch.test.js +4 -6
- package/package.json +1 -1
- package/payload/platform/lib/admin-access-password/__tests__/index.test.ts +28 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts +9 -0
- package/payload/platform/lib/admin-access-password/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/admin-access-password/dist/index.js +26 -0
- package/payload/platform/lib/admin-access-password/dist/index.js.map +1 -1
- package/payload/platform/lib/admin-access-password/src/index.ts +24 -0
- package/payload/platform/lib/models/dist/index.d.ts +7 -0
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +10 -0
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +10 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +4 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +20 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +1 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +11 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/server/{chunk-FBGIHWWM.js → chunk-J6WDAWFJ.js} +20 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/AccessGate-CU4Qw6M6.js +1 -0
- package/payload/server/public/assets/AdminLoginScreens-DUpRIM1h.js +1 -0
- package/payload/server/public/assets/AdminShell-DkoQSsqo.js +1 -0
- package/payload/server/public/assets/{Checkbox-8elc7oXU.js → Checkbox-DMA1hVhn.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-BIHiyyxU.js +1 -0
- package/payload/server/public/assets/admin-BHvOMcCh.js +1 -0
- package/payload/server/public/assets/{arc-DxSm8tli.js → arc-Dl9QFDgW.js} +1 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-Crq5RSDG.js +1 -0
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-7JSAh0vL.js → architectureDiagram-Q4EWVU46-CNLQUVi9.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-DzbKNqbH.js → audio-attachment-mime-DOBET-W1.js} +3 -3
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-DLoVmHKD.js → blockDiagram-DXYQGD6D-B-QxfVjk.js} +1 -1
- package/payload/server/public/assets/brand-4F9ZXBF8.css +1 -0
- package/payload/server/public/assets/{brand-Dh5UlVO2.js → brand-C7kj0USi.js} +1 -1
- package/payload/server/public/assets/browser-eLSiC7_b.js +1 -0
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-Nv1G0o9P.js → c4Diagram-AHTNJAMY-NuYFvPDU.js} +1 -1
- package/payload/server/public/assets/channel-KT66MFN2.js +1 -0
- package/payload/server/public/assets/chat-DedpVKUl.js +1 -0
- package/payload/server/public/assets/{chunk-2KRD3SAO-BpqPMhoA.js → chunk-2KRD3SAO-l5VL1KQm.js} +1 -1
- package/payload/server/public/assets/{chunk-336JU56O-DgXHlVU_.js → chunk-336JU56O-C5gVznC2.js} +2 -2
- package/payload/server/public/assets/chunk-426QAEUC-CWMiOm8Y.js +1 -0
- package/payload/server/public/assets/{chunk-4BX2VUAB-nwyZSZH8.js → chunk-4BX2VUAB-BtMVz_Sq.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-Tfxz9LHX.js → chunk-4TB4RGXK-C8-dmCuT.js} +1 -1
- package/payload/server/public/assets/{chunk-55IACEB6-6FMJQGXG.js → chunk-55IACEB6-C5gWvEJW.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-g2FgZF3D.js → chunk-5FUZZQ4R-BZ7VZoAC.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DtLwXsPH.js → chunk-5PVQY5BW-C_ajQOGC.js} +1 -1
- package/payload/server/public/assets/{chunk-67CJDMHE-K91CP5ZU.js → chunk-67CJDMHE-BJOR2dwK.js} +1 -1
- package/payload/server/public/assets/{chunk-7N4EOEYR-BGpCQhqK.js → chunk-7N4EOEYR-DvZLpquX.js} +1 -1
- package/payload/server/public/assets/{chunk-AA7GKIK3-jkDbInck.js → chunk-AA7GKIK3-h5tVsPlW.js} +1 -1
- package/payload/server/public/assets/{chunk-BSJP7CBP-mDosdzGs.js → chunk-BSJP7CBP-DLOF2-m3.js} +1 -1
- package/payload/server/public/assets/{chunk-CIAEETIT-DhBxewpQ.js → chunk-CIAEETIT-CQRQMPCf.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-B7c-9Emg.js → chunk-EDXVE4YY-K9-EfuM2.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Cqhhncox.js → chunk-ENJZ2VHE-DVoy6NvU.js} +1 -1
- package/payload/server/public/assets/{chunk-FMBD7UC4-BpDq6wj1.js → chunk-FMBD7UC4-CQn_2o2b.js} +1 -1
- package/payload/server/public/assets/{chunk-FOC6F5B3-Ds02-ktu.js → chunk-FOC6F5B3-CuN73goS.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-BTX5POFr.js → chunk-ICPOFSXX-CKhl9J-H.js} +2 -2
- package/payload/server/public/assets/{chunk-K5T4RW27-Du1PXXBU.js → chunk-K5T4RW27-CBskuQmq.js} +1 -1
- package/payload/server/public/assets/{chunk-KGLVRYIC-siasOAf8.js → chunk-KGLVRYIC-Chtjt8xK.js} +1 -1
- package/payload/server/public/assets/{chunk-LIHQZDEY-xf1rbZtf.js → chunk-LIHQZDEY-EOBiBNSH.js} +1 -1
- package/payload/server/public/assets/{chunk-ORNJ4GCN-DeTLQ_LD.js → chunk-ORNJ4GCN-uPPq-5MN.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DQ7_oVJn.js → chunk-OYMX7WX6-BRzbxJOT.js} +1 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DCzpF46A.js +1 -0
- package/payload/server/public/assets/{chunk-U2HBQHQK-CXmFUKgn.js → chunk-U2HBQHQK-Bndyn5nF.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Bj8-8Wkz.js → chunk-X2U36JSP-BspGBHXW.js} +1 -1
- package/payload/server/public/assets/{chunk-XPW4576I-Con3TXqt.js → chunk-XPW4576I-HgXQ2k9h.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Dx8BHGWf.js → chunk-YZCP3GAM-C7oTyCnw.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-Dp4Q5Y-f.js → chunk-ZZ45TVLE-CufWa7QL.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-QOU4HzJJ.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-DcOUai3Z.js +1 -0
- package/payload/server/public/assets/clone-CHh05KN-.js +1 -0
- package/payload/server/public/assets/{cose-bilkent-S5V4N54A-pZiCv69E.js → cose-bilkent-S5V4N54A-BM3yEbF-.js} +1 -1
- package/payload/server/public/assets/{dagre-CLqhEgbL.js → dagre-C7WHNZO8.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-BCxE8iyk.js → dagre-KV5264BT-bcZx3l06.js} +1 -1
- package/payload/server/public/assets/data-BcoBY39U.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-slUEdZzz.js → diagram-5BDNPKRD-B7VotaMF.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-DPcraMfu.js → diagram-G4DWMVQ6-CWWvEsFx.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DR6luhGK.js → diagram-MMDJMWI5-DYHVkTYJ.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-Jap1B4wA.js → diagram-TYMM5635-CHeB6Ama.js} +1 -1
- package/payload/server/public/assets/{dist-Dbh7HrZX.js → dist-CjjtmoWL.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-DJKUs2hO.js → erDiagram-SMLLAGMA-C9gog8QP.js} +1 -1
- package/payload/server/public/assets/{flatten-Cl1Bc3dR.js → flatten-QcJDm7yK.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-C8W-ZZ9W.js → flowDiagram-DWJPFMVM-B2O9lKTh.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DYCX4Xu2.js → ganttDiagram-T4ZO3ILL-DEa4AwbR.js} +1 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-BC-u4jgy.js +1 -0
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CZu_fpgS.js → gitGraphDiagram-UUTBAWPF-BjXPQpBL.js} +1 -1
- package/payload/server/public/assets/{graph-DKSjcpmR.js → graph-C7Hye_vp.js} +2 -2
- package/payload/server/public/assets/{graph-labels-CVWPQgBV.js → graph-labels-YYgGsEVd.js} +1 -1
- package/payload/server/public/assets/{graphlib-Bdp7TA4y.js → graphlib-CBevn2DP.js} +1 -1
- package/payload/server/public/assets/info-OMHHGYJF-DPUetTz-.js +1 -0
- package/payload/server/public/assets/infoDiagram-42DDH7IO-q2dl09-M.js +2 -0
- package/payload/server/public/assets/{isEmpty-D1pGOD1J.js → isEmpty-BO6BAEn7.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-B7KfIX6z.js → ishikawaDiagram-UXIWVN3A-CPLfpvqv.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CSDwBfhF.js → journeyDiagram-VCZTEJTY-CTHe8MiD.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CWzcEKTr.js → kanban-definition-6JOO6SKY-Bm9h1O3Y.js} +1 -1
- package/payload/server/public/assets/{line-BNQSlbYn.js → line-C31b0rtY.js} +1 -1
- package/payload/server/public/assets/{linear-BN6kGN93.js → linear-Cfm_8_pU.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CcFhkElq.js → mermaid-parser.core-B3tGwOcE.js} +2 -2
- package/payload/server/public/assets/{mermaid.core-BsIeJ7Cc.js → mermaid.core-BM3s85ZW.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CQVzj6D_.js → mindmap-definition-QFDTVHPH-CaGv_mIB.js} +1 -1
- package/payload/server/public/assets/operator-WsXhcbBF.js +1 -0
- package/payload/server/public/assets/{ordinal-CBZeH4Yp.js → ordinal-jLCwuvYg.js} +1 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-BcfR-ZwA.js +1 -0
- package/payload/server/public/assets/page-BhHTnqv4.js +1 -0
- package/payload/server/public/assets/pie-ZZUOXDRM-BiKgZdNB.js +1 -0
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-DnrQ9fyn.js → pieDiagram-DEJITSTG-BhAXps4u.js} +1 -1
- package/payload/server/public/assets/public-ViXjC_dA.js +6 -0
- package/payload/server/public/assets/public-next-BKECyMz2.js +1 -0
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BQWlCyWi.js → quadrantDiagram-34T5L4WZ-BWtTdNs8.js} +1 -1
- package/payload/server/public/assets/radar-PYXPWWZC-nvCjiW_J.js +1 -0
- package/payload/server/public/assets/{reduce-PuPlFPRX.js → reduce-Dmi_NdVH.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-Du_vZhU1.js → requirementDiagram-MS252O5E-CWU0qCcP.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-Cf6Z8GPQ.js → sankeyDiagram-XADWPNL6-DYvutQld.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CS8GVol8.js → sequenceDiagram-FGHM5R23-Cir0hBWS.js} +1 -1
- package/payload/server/public/assets/{src-BoaldmnP.js → src-CwB968DO.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-Bv1NW2F1.js → stateDiagram-FHFEXIEX-Be-h8YSS.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-CAnmjSj7.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-ClGYAsr0.js → timeline-definition-GMOUNBTQ-C3C4Wuyk.js} +1 -1
- package/payload/server/public/assets/treeView-SZITEDCU-BinXCVyM.js +1 -0
- package/payload/server/public/assets/treemap-W4RFUUIX-CSmh20Ze.js +1 -0
- package/payload/server/public/assets/{useSelectionMode-FIodJKzS.js → useSelectionMode-CG_Iel5F.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-C2wTcxQT.js → vennDiagram-DHZGUBPP-mDclw0Sa.js} +1 -1
- package/payload/server/public/assets/wardley-RL74JXVD-BiCmRKWx.js +1 -0
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-D86-ivEx.js → wardleyDiagram-NUSXRM2D-mvk-YA9g.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Ba5WAN8P.js → xychartDiagram-5P7HB3ND-9M7k1hmD.js} +1 -1
- package/payload/server/public/browser.html +8 -8
- package/payload/server/public/chat.html +11 -11
- package/payload/server/public/data.html +7 -7
- package/payload/server/public/graph.html +10 -10
- package/payload/server/public/index.html +10 -10
- package/payload/server/public/operator.html +13 -13
- package/payload/server/public/public-next.html +24 -0
- package/payload/server/public/public.html +9 -8
- package/payload/server/server.js +819 -614
- package/dist/__tests__/onboarding-state-readback.test.js +0 -61
- package/dist/__tests__/rss-sampler-installer.test.js +0 -27
- package/dist/onboarding-readback.js +0 -27
- package/payload/server/public/assets/AdminLoginScreens-BZIA9Z6o.js +0 -1
- package/payload/server/public/assets/AdminShell-iazLHsk7.js +0 -1
- package/payload/server/public/assets/admin-BEx6o3fa.js +0 -1
- package/payload/server/public/assets/architecture-YZFGNWBL-6g9jRVgc.js +0 -1
- package/payload/server/public/assets/brand-CmMZe4RK.css +0 -1
- package/payload/server/public/assets/browser-D16sPVkI.js +0 -1
- package/payload/server/public/assets/channel-BgQLJanG.js +0 -1
- package/payload/server/public/assets/chat-x4PnXhkd.js +0 -1
- package/payload/server/public/assets/chunk-426QAEUC-Dr_XVuUq.js +0 -1
- package/payload/server/public/assets/chunk-QZHKN3VN-DF4o9HRJ.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DAbPKU6u.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BKuFQLcv.js +0 -1
- package/payload/server/public/assets/clone-DnNHGhNe.js +0 -1
- package/payload/server/public/assets/data-DqG45sq0.js +0 -1
- package/payload/server/public/assets/file-download-BvGS7Qmi.js +0 -1
- package/payload/server/public/assets/gitGraph-7Q5UKJZL-g7mvu6IY.js +0 -1
- package/payload/server/public/assets/info-OMHHGYJF-DZqJuIkB.js +0 -1
- package/payload/server/public/assets/infoDiagram-42DDH7IO-cGfGccHz.js +0 -2
- package/payload/server/public/assets/operator-Cnzbhdh2.js +0 -1
- package/payload/server/public/assets/packet-4T2RLAQJ-Hn8rlHpy.js +0 -1
- package/payload/server/public/assets/page-CH8JQkQN.js +0 -1
- package/payload/server/public/assets/pie-ZZUOXDRM-BPGWVqBm.js +0 -1
- package/payload/server/public/assets/public-CA90VhI9.js +0 -6
- package/payload/server/public/assets/radar-PYXPWWZC-DMdLrj3E.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-BGUCxPmp.js +0 -1
- package/payload/server/public/assets/treeView-SZITEDCU-CWxofUbI.js +0 -1
- package/payload/server/public/assets/treemap-W4RFUUIX-Cfgb_ZG0.js +0 -1
- package/payload/server/public/assets/wardley-RL74JXVD-B45olYjj.js +0 -1
- /package/payload/server/public/assets/{file-download-qc_xy7Az.css → OperatorConversations-qc_xy7Az.css} +0 -0
- /package/payload/server/public/assets/{_baseFor-brRjpUOX.js → _baseFor-D8P3gUw3.js} +0 -0
- /package/payload/server/public/assets/{array-BGFCBI0e.js → array-CLwNaqU1.js} +0 -0
- /package/payload/server/public/assets/{chunk-Pqm5yXtL.js → chunk-CAM3fms7.js} +0 -0
- /package/payload/server/public/assets/{cytoscape.esm-TvRJ2tGX.js → cytoscape.esm-mZ4wTuB7.js} +0 -0
- /package/payload/server/public/assets/{defaultLocale-CRZydyG6.js → defaultLocale-D_VMtRaY.js} +0 -0
- /package/payload/server/public/assets/{init-B8gtcn7T.js → init-vVpfz1D6.js} +0 -0
- /package/payload/server/public/assets/{katex-RxgSu_dy.js → katex-DaHGEgm7.js} +0 -0
- /package/payload/server/public/assets/{path-DZF-JdEe.js → path-CuyvWNAH.js} +0 -0
- /package/payload/server/public/assets/{preload-helper-CQ36nxok.js → preload-helper-TKOBYGYD.js} +0 -0
- /package/payload/server/public/assets/{rough.esm-6CnTHTkH.js → rough.esm-JX0wREDd.js} +0 -0
|
@@ -10,7 +10,7 @@ import { buildClaudePtysSliceUnitFile } from "../port-resolution.js";
|
|
|
10
10
|
test("buildClaudePtysSliceUnitFile emits a valid systemd slice unit", () => {
|
|
11
11
|
const unit = buildClaudePtysSliceUnitFile();
|
|
12
12
|
assert.match(unit, /^\[Unit\]$/m);
|
|
13
|
-
assert.match(unit, /^Description
|
|
13
|
+
assert.match(unit, /^Description=.+$/m);
|
|
14
14
|
assert.match(unit, /^\[Slice\]$/m);
|
|
15
15
|
assert.match(unit, /^\[Install\]$/m);
|
|
16
16
|
assert.match(unit, /^WantedBy=default\.target$/m);
|
|
@@ -8,7 +8,7 @@ import { buildCloudflaredSliceUnitFile } from "../port-resolution.js";
|
|
|
8
8
|
test("buildCloudflaredSliceUnitFile emits a valid systemd slice unit", () => {
|
|
9
9
|
const unit = buildCloudflaredSliceUnitFile();
|
|
10
10
|
assert.match(unit, /^\[Unit\]$/m);
|
|
11
|
-
assert.match(unit, /^Description
|
|
11
|
+
assert.match(unit, /^Description=.+$/m);
|
|
12
12
|
assert.match(unit, /^\[Slice\]$/m);
|
|
13
13
|
assert.match(unit, /^\[Install\]$/m);
|
|
14
14
|
assert.match(unit, /^WantedBy=default\.target$/m);
|
|
@@ -31,10 +31,10 @@ test("installSystemDeps has darwin branch that calls setMacosHostnameViaScutil o
|
|
|
31
31
|
assert.match(SRC, /darwin-hostname-mode=brand-fallback/, "brand-fallback path must emit observability log");
|
|
32
32
|
});
|
|
33
33
|
test("installSystemDeps darwin branch installs DARWIN_BASE_DEPS via brew", () => {
|
|
34
|
-
// The
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
|
|
34
|
+
// The darwin path feeds the shared dep set to installAllBrewPackages. The
|
|
35
|
+
// exact membership of DARWIN_BASE_DEPS is asserted behaviourally in
|
|
36
|
+
// brew-resolve.test.ts (DARWIN_BASE_DEPS_FIXTURE); here we only pin that the
|
|
37
|
+
// branch still routes that set through brew.
|
|
38
38
|
assert.match(SRC, /installAllBrewPackages\(DARWIN_BASE_DEPS,\s*logFile\)/);
|
|
39
39
|
});
|
|
40
40
|
test("installCloudflared darwin branch logs the documented skip and brew-installs cloudflared", () => {
|
|
@@ -58,8 +58,6 @@ test("installService darwin branch delegates to installServiceDarwin (launchd pa
|
|
|
58
58
|
// and installServiceDarwin writes the plist + bootstraps it via launchctl.
|
|
59
59
|
assert.match(SRC, /platform\s*===\s*"darwin"\s*\)\s*\{\s*installServiceDarwin\(\)/);
|
|
60
60
|
assert.match(SRC, /launchctl["']?,\s*\[["']bootstrap["']/);
|
|
61
|
-
assert.match(SRC, /launchd-plist=\$\{path\}\s+loaded=true/, "successful bootstrap must emit launchd-plist=… loaded=true");
|
|
62
|
-
assert.match(SRC, /launchd-plist=\$\{path\}\s+loaded=false/, "failed bootstrap must emit launchd-plist=… loaded=false");
|
|
63
61
|
});
|
|
64
62
|
test("installNodejs darwin branch brew-installs the `nodejs` alias name (resolver hops to node@22)", () => {
|
|
65
63
|
// The shared call site uses the apt-style `nodejs` name. brew-resolve.ts
|
package/package.json
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
verifyAccessPassword,
|
|
10
10
|
anyAccessPasswordConfigured,
|
|
11
11
|
accessStoreUnreadable,
|
|
12
|
+
accessPasswordCollides,
|
|
12
13
|
migrateLegacyRemotePassword,
|
|
13
14
|
} from '../src/index'
|
|
14
15
|
|
|
@@ -61,6 +62,33 @@ describe('admin-access-password', () => {
|
|
|
61
62
|
expect(await verifyAccessPassword('anything', f)).toBeNull()
|
|
62
63
|
})
|
|
63
64
|
|
|
65
|
+
it('accessPasswordCollides: true when a DIFFERENT admin already has that password', async () => {
|
|
66
|
+
const f = tmpUsers([{ userId: 'a', pin: 'x' }, { userId: 'b', pin: 'y' }])
|
|
67
|
+
await setAccessPassword('a', 'Sw0rdfish!', f)
|
|
68
|
+
// b is choosing the same password a already uses
|
|
69
|
+
expect(await accessPasswordCollides('Sw0rdfish!', f, 'b')).toBe(true)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('accessPasswordCollides: false when only the excluded admin holds that password', async () => {
|
|
73
|
+
const f = tmpUsers([{ userId: 'a', pin: 'x' }, { userId: 'b', pin: 'y' }])
|
|
74
|
+
await setAccessPassword('a', 'Sw0rdfish!', f)
|
|
75
|
+
// a rotating to the same value it already has is not a cross-admin collision
|
|
76
|
+
expect(await accessPasswordCollides('Sw0rdfish!', f, 'a')).toBe(false)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('accessPasswordCollides: false for a password no other admin uses', async () => {
|
|
80
|
+
const f = tmpUsers([{ userId: 'a', pin: 'x' }, { userId: 'b', pin: 'y' }])
|
|
81
|
+
await setAccessPassword('a', 'Sw0rdfish!', f)
|
|
82
|
+
expect(await accessPasswordCollides('Different1!', f, 'b')).toBe(false)
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
it('accessPasswordCollides: false when the store is unreadable', async () => {
|
|
86
|
+
const dir = mkdtempSync(join(tmpdir(), 'aapc-'))
|
|
87
|
+
const corrupt = join(dir, 'users.json')
|
|
88
|
+
writeFileSync(corrupt, '{ not json')
|
|
89
|
+
expect(await accessPasswordCollides('anything', corrupt, 'b')).toBe(false)
|
|
90
|
+
})
|
|
91
|
+
|
|
64
92
|
it('accessStoreUnreadable: false for absent/clean, true for corrupt (fail-closed signal)', () => {
|
|
65
93
|
const dir = mkdtempSync(join(tmpdir(), 'aapu-'))
|
|
66
94
|
const absent = join(dir, 'users.json')
|
|
@@ -13,6 +13,15 @@ export declare function setAccessPassword(userId: string, password: string, user
|
|
|
13
13
|
export declare function clearAccessPassword(userId: string, usersFile: string): void;
|
|
14
14
|
/** Return the userId whose accessHash matches, or null. */
|
|
15
15
|
export declare function verifyAccessPassword(password: string, usersFile: string): Promise<string | null>;
|
|
16
|
+
/**
|
|
17
|
+
* True when some admin OTHER than excludeUserId already has an accessHash that
|
|
18
|
+
* matches `password`. Used by the set/change surfaces to refuse a value that
|
|
19
|
+
* would collide with another admin's perimeter credential — the scan-based
|
|
20
|
+
* verify attributes a login to the first matching record, so two admins sharing
|
|
21
|
+
* a password lets one silently overwrite the other. An unreadable store returns
|
|
22
|
+
* false: the subsequent write is what owns the read-fault error path.
|
|
23
|
+
*/
|
|
24
|
+
export declare function accessPasswordCollides(password: string, usersFile: string, excludeUserId: string): Promise<boolean>;
|
|
16
25
|
/** True when at least one record carries an accessHash. */
|
|
17
26
|
export declare function anyAccessPasswordConfigured(usersFile: string): boolean;
|
|
18
27
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAWD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;AAED,iBAAe,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS7E;AAiBD,mFAAmF;AACnF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1G;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAQ3E;AAED,2DAA2D;AAC3D,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAStG;AAED,2DAA2D;AAC3D,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAItE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAGhE;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,gBAAgB,GAAG,eAAe,GAAG,qBAAqB,CAAA;AAEnG;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,aAAa,CAgBf;AAED;kEACkE;AAClE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAItE;AAED,OAAO,EAAE,WAAW,IAAI,mBAAmB,EAAE,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;CACrB;AAWD,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI1E;AAED,iBAAe,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAS7E;AAiBD,mFAAmF;AACnF,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM1G;AAED,qEAAqE;AACrE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAQ3E;AAED,2DAA2D;AAC3D,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAStG;AAED;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED,2DAA2D;AAC3D,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAItE;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAGhE;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,gBAAgB,GAAG,eAAe,GAAG,qBAAqB,CAAA;AAEnG;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,aAAa,CAgBf;AAED;kEACkE;AAClE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAItE;AAED,OAAO,EAAE,WAAW,IAAI,mBAAmB,EAAE,CAAA"}
|
|
@@ -4,6 +4,7 @@ exports.hashAccessPassword = hashAccessPassword;
|
|
|
4
4
|
exports.setAccessPassword = setAccessPassword;
|
|
5
5
|
exports.clearAccessPassword = clearAccessPassword;
|
|
6
6
|
exports.verifyAccessPassword = verifyAccessPassword;
|
|
7
|
+
exports.accessPasswordCollides = accessPasswordCollides;
|
|
7
8
|
exports.anyAccessPasswordConfigured = anyAccessPasswordConfigured;
|
|
8
9
|
exports.accessStoreUnreadable = accessStoreUnreadable;
|
|
9
10
|
exports.migrateLegacyRemotePassword = migrateLegacyRemotePassword;
|
|
@@ -102,6 +103,31 @@ async function verifyAccessPassword(password, usersFile) {
|
|
|
102
103
|
}
|
|
103
104
|
return null;
|
|
104
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* True when some admin OTHER than excludeUserId already has an accessHash that
|
|
108
|
+
* matches `password`. Used by the set/change surfaces to refuse a value that
|
|
109
|
+
* would collide with another admin's perimeter credential — the scan-based
|
|
110
|
+
* verify attributes a login to the first matching record, so two admins sharing
|
|
111
|
+
* a password lets one silently overwrite the other. An unreadable store returns
|
|
112
|
+
* false: the subsequent write is what owns the read-fault error path.
|
|
113
|
+
*/
|
|
114
|
+
async function accessPasswordCollides(password, usersFile, excludeUserId) {
|
|
115
|
+
let users;
|
|
116
|
+
try {
|
|
117
|
+
users = readUsers(usersFile);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
for (const u of users) {
|
|
123
|
+
if (u.userId === excludeUserId)
|
|
124
|
+
continue;
|
|
125
|
+
if (typeof u.accessHash === 'string' && (await matchesHash(password, u.accessHash))) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
105
131
|
/** True when at least one record carries an accessHash. */
|
|
106
132
|
function anyAccessPasswordConfigured(usersFile) {
|
|
107
133
|
let users;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AA4BA,gDAIC;AA6BD,8CAMC;AAGD,kDAQC;AAGD,oDASC;AAGD,kEAIC;AASD,sDAGC;AAYD,kEAoBC;AAID,oDAIC;AAEuB,0CAAmB;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -90,6 +90,30 @@ export async function verifyAccessPassword(password: string, usersFile: string):
|
|
|
90
90
|
return null
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
/**
|
|
94
|
+
* True when some admin OTHER than excludeUserId already has an accessHash that
|
|
95
|
+
* matches `password`. Used by the set/change surfaces to refuse a value that
|
|
96
|
+
* would collide with another admin's perimeter credential — the scan-based
|
|
97
|
+
* verify attributes a login to the first matching record, so two admins sharing
|
|
98
|
+
* a password lets one silently overwrite the other. An unreadable store returns
|
|
99
|
+
* false: the subsequent write is what owns the read-fault error path.
|
|
100
|
+
*/
|
|
101
|
+
export async function accessPasswordCollides(
|
|
102
|
+
password: string,
|
|
103
|
+
usersFile: string,
|
|
104
|
+
excludeUserId: string,
|
|
105
|
+
): Promise<boolean> {
|
|
106
|
+
let users: AccessUserEntry[]
|
|
107
|
+
try { users = readUsers(usersFile) } catch { return false }
|
|
108
|
+
for (const u of users) {
|
|
109
|
+
if (u.userId === excludeUserId) continue
|
|
110
|
+
if (typeof u.accessHash === 'string' && (await matchesHash(password, u.accessHash))) {
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
|
|
93
117
|
/** True when at least one record carries an accessHash. */
|
|
94
118
|
export function anyAccessPasswordConfigured(usersFile: string): boolean {
|
|
95
119
|
let users: AccessUserEntry[]
|
|
@@ -17,4 +17,11 @@ export declare function modelDisplayName(id: string): string;
|
|
|
17
17
|
* is rejected before the fork. */
|
|
18
18
|
export declare const SELECTABLE_MODELS: readonly string[];
|
|
19
19
|
export declare function isSelectableModel(id: string): boolean;
|
|
20
|
+
/** Strip Claude Code's `[1m]` context-extension suffix so a selectable id
|
|
21
|
+
* (`claude-opus-4-8[1m]`) compares equal to the live API/JSONL `message.model`
|
|
22
|
+
* (suffix stripped upstream → `claude-opus-4-8`). Ids without the suffix pass
|
|
23
|
+
* through. The /chat picker uses this to decide whether a chosen model is a
|
|
24
|
+
* real change from the running one — a raw `selected !== live` compare is
|
|
25
|
+
* always true for `[1m]` models. */
|
|
26
|
+
export declare function baseModelId(id: string): string;
|
|
20
27
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIvD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;qEAEqE;AACrE,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAItD,CAAC;AAEF;+DAC+D;AAC/D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;mCAGmC;AACnC,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAA4C,CAAC;AAC5F,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAErD"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,eAAO,MAAM,UAAU,wBAAwB,CAAC;AAChD,eAAO,MAAM,YAAY,sBAAsB,CAAC;AAChD,eAAO,MAAM,WAAW,qBAAqB,CAAC;AAE9C,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIvD,CAAC;AAEF,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;qEAEqE;AACrE,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAItD,CAAC;AAEF;+DAC+D;AAC/D,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;mCAGmC;AACnC,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAA4C,CAAC;AAC5F,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;qCAKqC;AACrC,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE9C"}
|
|
@@ -7,6 +7,7 @@ exports.SELECTABLE_MODELS = exports.MODEL_DISPLAY_NAMES = exports.MODEL_CONTEXT_
|
|
|
7
7
|
exports.contextWindow = contextWindow;
|
|
8
8
|
exports.modelDisplayName = modelDisplayName;
|
|
9
9
|
exports.isSelectableModel = isSelectableModel;
|
|
10
|
+
exports.baseModelId = baseModelId;
|
|
10
11
|
// Opus defaults to the 1M-context variant ([1m] is Claude Code's
|
|
11
12
|
// context-extension suffix, valid in settings.json "model" and agent
|
|
12
13
|
// frontmatter); Sonnet/Haiku stay on the standard 200k window.
|
|
@@ -43,4 +44,13 @@ exports.SELECTABLE_MODELS = [exports.OPUS_MODEL, exports.SONNET_MODEL, exports.H
|
|
|
43
44
|
function isSelectableModel(id) {
|
|
44
45
|
return exports.SELECTABLE_MODELS.includes(id);
|
|
45
46
|
}
|
|
47
|
+
/** Strip Claude Code's `[1m]` context-extension suffix so a selectable id
|
|
48
|
+
* (`claude-opus-4-8[1m]`) compares equal to the live API/JSONL `message.model`
|
|
49
|
+
* (suffix stripped upstream → `claude-opus-4-8`). Ids without the suffix pass
|
|
50
|
+
* through. The /chat picker uses this to decide whether a chosen model is a
|
|
51
|
+
* real change from the running one — a raw `selected !== live` compare is
|
|
52
|
+
* always true for `[1m]` models. */
|
|
53
|
+
function baseModelId(id) {
|
|
54
|
+
return id.replace(/\[1m\]$/, "");
|
|
55
|
+
}
|
|
46
56
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,iEAAiE;AACjE,6CAA6C;;;AAgB7C,sCAEC;AAaD,4CAEC;AAOD,8CAEC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,0DAA0D;AAC1D,iEAAiE;AACjE,6CAA6C;;;AAgB7C,sCAEC;AAaD,4CAEC;AAOD,8CAEC;AAQD,kCAEC;AAlDD,iEAAiE;AACjE,qEAAqE;AACrE,+DAA+D;AAClD,QAAA,UAAU,GAAG,qBAAqB,CAAC;AACnC,QAAA,YAAY,GAAG,mBAAmB,CAAC;AACnC,QAAA,WAAW,GAAG,kBAAkB,CAAC;AAEjC,QAAA,oBAAoB,GAA2B;IAC1D,CAAC,kBAAU,CAAC,EAAE,SAAS;IACvB,CAAC,oBAAY,CAAC,EAAE,OAAO;IACvB,CAAC,mBAAW,CAAC,EAAE,OAAO;CACvB,CAAC;AAEF,wEAAwE;AACxE,SAAgB,aAAa,CAAC,KAAa;IACzC,OAAO,4BAAoB,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC;AAChD,CAAC;AAED;;qEAEqE;AACxD,QAAA,mBAAmB,GAA2B;IACzD,CAAC,kBAAU,CAAC,EAAE,uBAAuB;IACrC,CAAC,oBAAY,CAAC,EAAE,YAAY;IAC5B,CAAC,mBAAW,CAAC,EAAE,WAAW;CAC3B,CAAC;AAEF;+DAC+D;AAC/D,SAAgB,gBAAgB,CAAC,EAAU;IACzC,OAAO,2BAAmB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;AACvC,CAAC;AAED;;;mCAGmC;AACtB,QAAA,iBAAiB,GAAsB,CAAC,kBAAU,EAAE,oBAAY,EAAE,mBAAW,CAAC,CAAC;AAC5F,SAAgB,iBAAiB,CAAC,EAAU;IAC1C,OAAO,yBAAiB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACxC,CAAC;AAED;;;;;qCAKqC;AACrC,SAAgB,WAAW,CAAC,EAAU;IACpC,OAAO,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -43,3 +43,13 @@ export const SELECTABLE_MODELS: readonly string[] = [OPUS_MODEL, SONNET_MODEL, H
|
|
|
43
43
|
export function isSelectableModel(id: string): boolean {
|
|
44
44
|
return SELECTABLE_MODELS.includes(id);
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
/** Strip Claude Code's `[1m]` context-extension suffix so a selectable id
|
|
48
|
+
* (`claude-opus-4-8[1m]`) compares equal to the live API/JSONL `message.model`
|
|
49
|
+
* (suffix stripped upstream → `claude-opus-4-8`). Ids without the suffix pass
|
|
50
|
+
* through. The /chat picker uses this to decide whether a chosen model is a
|
|
51
|
+
* real change from the running one — a raw `selected !== live` compare is
|
|
52
|
+
* always true for `[1m]` models. */
|
|
53
|
+
export function baseModelId(id: string): string {
|
|
54
|
+
return id.replace(/\[1m\]$/, "");
|
|
55
|
+
}
|
|
@@ -9,7 +9,7 @@ import { resolve, join } from "node:path";
|
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
10
|
import { appendFileSync, cpSync, existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
11
11
|
import { writeAdminEntry, removeAdminFromAccount } from "../../../../lib/admins-write/dist/index.js";
|
|
12
|
-
import { setAccessPassword as setAccessPasswordHash, clearAccessPassword as clearAccessPasswordHash } from "../../../../lib/admin-access-password/dist/index.js";
|
|
12
|
+
import { setAccessPassword as setAccessPasswordHash, clearAccessPassword as clearAccessPasswordHash, accessPasswordCollides } from "../../../../lib/admin-access-password/dist/index.js";
|
|
13
13
|
import { embed } from "../../../../lib/embed-client/dist/index.js";
|
|
14
14
|
import { requirePortEnv } from "../../../../lib/require-port-env/dist/index.js";
|
|
15
15
|
import { deviceUrlBlock } from "../../../../lib/device-url/dist/index.js";
|
|
@@ -2072,6 +2072,9 @@ server.tool("remote-auth-set-password", "Set an admin's remote access password
|
|
|
2072
2072
|
isError: true,
|
|
2073
2073
|
};
|
|
2074
2074
|
}
|
|
2075
|
+
if (await accessPasswordCollides(password, USERS_FILE, targetUserId)) {
|
|
2076
|
+
return { content: [{ type: "text", text: `That password is already in use by another admin. Choose a different one.` }], isError: true };
|
|
2077
|
+
}
|
|
2075
2078
|
try {
|
|
2076
2079
|
await setAccessPasswordHash(targetUserId, password, USERS_FILE);
|
|
2077
2080
|
console.error(`[admin] remote-access-password set userId=${targetUserId.slice(0, 8)}`);
|