shioricode 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/dist/bin.cjs +386 -142
- package/dist/bin.mjs +386 -142
- package/dist/client/assets/{ArtifactPanel-1Tg5ZLm5.js → ArtifactPanel-ClA97FO8.js} +2 -2
- package/dist/client/assets/{ChatMarkdown-BvwoXC6z.js → ChatMarkdown-DkldD1_B.js} +2 -2
- package/dist/client/assets/{DiffPanel-D-xp36wD.js → DiffPanel-BYSH-G7M.js} +3 -3
- package/dist/client/assets/{DiffPanelShell-DdBr4p9c.js → DiffPanelShell-Ce2wOE9L.js} +2 -2
- package/dist/client/assets/{DiffWorkerPoolProvider--93ReMXi.js → DiffWorkerPoolProvider-DjSdGkRQ.js} +2 -2
- package/dist/client/assets/{NoActiveThreadState-B_C5Y_aO.js → NoActiveThreadState-CVDfDuF2.js} +2 -2
- package/dist/client/assets/{ProviderModelPicker-BWTkQW8f.js → ProviderModelPicker-BFlX8lZL.js} +2 -2
- package/dist/client/assets/SettingsPanels-_8_YaXgc.js +4 -0
- package/dist/client/assets/{_chat-BhqvWJHj.js → _chat-CQ5UewiP.js} +2 -2
- package/dist/client/assets/_chat._threadId-5846z-_l.js +289 -0
- package/dist/client/assets/{_chat.index-oZTnMcB3.js → _chat.index-DI7egWLc.js} +2 -2
- package/dist/client/assets/automations-D6SQKJ83.js +2 -0
- package/dist/client/assets/{badge-BkzSFcY-.js → badge-iReKY3O4.js} +2 -2
- package/dist/client/assets/{clientSettings--1UP2ayD.js → clientSettings-DFgmWajw.js} +2 -2
- package/dist/client/assets/{collapsible-CqRg_DyH.js → collapsible-BEW6Xu4N.js} +2 -2
- package/dist/client/assets/{dialog-C7Ppq2qI.js → dialog-CZ2IjObB.js} +2 -2
- package/dist/client/assets/{gitReactQuery-BBOGuHot.js → gitReactQuery-BxToLb49.js} +2 -2
- package/dist/client/assets/{index-DvBh1mNh.js → index-B42nGfCf.js} +5 -5
- package/dist/client/assets/{input-emuaAuIe.js → input-CthhcRBE.js} +2 -2
- package/dist/client/assets/pull-requests-DGa0NhIZ.js +46 -0
- package/dist/client/assets/{queuedTurnsStore-I4LoXHLF.js → queuedTurnsStore-CYufNsaQ.js} +2 -2
- package/dist/client/assets/{scroll-area-kK2XF1gm.js → scroll-area-D6P_hAXV.js} +2 -2
- package/dist/client/assets/{separator-CSqq2xHm.js → separator-ByukCTaZ.js} +2 -2
- package/dist/client/assets/{settings-C9R1j3GG.js → settings-BwPioqTL.js} +2 -2
- package/dist/client/assets/{settings.appearance-Cac_fbGk.js → settings.appearance-DxQzPuf5.js} +2 -2
- package/dist/client/assets/settings.archived-BSqIxOKY.js +2 -0
- package/dist/client/assets/{settings.computer-use-BL801Zu5.js → settings.computer-use-DuuUffvc.js} +2 -2
- package/dist/client/assets/{settings.credits-Brx-cGXe.js → settings.credits-DiXAbJQa.js} +2 -2
- package/dist/client/assets/settings.general-DjIbwGSI.js +2 -0
- package/dist/client/assets/{settings.mcp-DEMm4v5q.js → settings.mcp-CHZOA1L-.js} +2 -2
- package/dist/client/assets/{settings.mobile-DF1raoba.js → settings.mobile-D3UiSzxp.js} +2 -2
- package/dist/client/assets/{settings.plugins-CewrpoKP.js → settings.plugins-qo7Fls2x.js} +2 -2
- package/dist/client/assets/{settings.remote-BufK_lG_.js → settings.remote-CmdhJhKY.js} +2 -2
- package/dist/client/assets/{settings.skills-Cz9xy1ba.js → settings.skills-UB5Wtkl5.js} +2 -2
- package/dist/client/assets/{settings.theme-builder-BU_DRAvo.js → settings.theme-builder-CnwNYRga.js} +2 -2
- package/dist/client/assets/{skillsMcpShared-DxxY1mEt.js → skillsMcpShared-CiunLdEL.js} +2 -2
- package/dist/client/assets/{store-BQMb1nBV.js → store-LT9wKN7R.js} +3 -3
- package/dist/client/assets/{terminalStateStore-C38k-Eaw.js → terminalStateStore-B-V7Awi_.js} +2 -2
- package/dist/client/assets/{textarea-DXuuOfmM.js → textarea-DAzODx1v.js} +2 -2
- package/dist/client/assets/{toggle-group-CvAnsecf.js → toggle-group-CMWeXyeK.js} +2 -2
- package/dist/client/assets/{toggle-nUm5N7vp.js → toggle-uzFsauJb.js} +2 -2
- package/dist/client/assets/{uiStateStore-Di3ieZaJ.js → uiStateStore-CgvPrTF8.js} +2 -2
- package/dist/client/assets/{useHandleNewThread-WYMZPumx.js → useHandleNewThread-Chs2blac.js} +2 -2
- package/dist/client/assets/{useSettings-DOuHg9jg.js → useSettings-CaigvboL.js} +2 -2
- package/dist/client/assets/{useTheme-Dhz9U3on.js → useTheme-7QjQMsSZ.js} +2 -2
- package/dist/client/assets/{vendor-ui-DmvKhMzf.js → vendor-ui-Ds9VgrYb.js} +2 -2
- package/dist/client/index.html +12 -12
- package/package.json +1 -1
- package/dist/client/assets/SettingsPanels-DGYlfoWv.js +0 -4
- package/dist/client/assets/_chat._threadId-Blwb3CRP.js +0 -289
- package/dist/client/assets/automations-ChGelqHO.js +0 -2
- package/dist/client/assets/pull-requests-xKFO2G81.js +0 -46
- package/dist/client/assets/settings.archived-KRU4XARw.js +0 -2
- package/dist/client/assets/settings.general-BXcV60tY.js +0 -2
package/dist/bin.cjs
CHANGED
|
@@ -72458,42 +72458,112 @@ var RemoteStateStore = class {
|
|
|
72458
72458
|
const execFile$10 = (0, node_util.promisify)(node_child_process.execFile);
|
|
72459
72459
|
const SERVICE_PORT = 3773;
|
|
72460
72460
|
const RECOVERY_USERNAME = "recovery";
|
|
72461
|
+
const SERVICE_LAYOUT_VERSION = 1;
|
|
72462
|
+
function invokingUsername() {
|
|
72463
|
+
const sudoUser = process.env.SUDO_USER?.trim();
|
|
72464
|
+
if (sudoUser && sudoUser !== "root") return sudoUser;
|
|
72465
|
+
return node_os.default.userInfo().username;
|
|
72466
|
+
}
|
|
72467
|
+
function invokingUid() {
|
|
72468
|
+
const sudoUid = Number(process.env.SUDO_UID);
|
|
72469
|
+
if (Number.isInteger(sudoUid) && sudoUid >= 0) return sudoUid;
|
|
72470
|
+
return typeof process.getuid === "function" ? process.getuid() : 0;
|
|
72471
|
+
}
|
|
72472
|
+
function defaultAccount(platform) {
|
|
72473
|
+
if (platform === "darwin") return "_shioricode";
|
|
72474
|
+
if (platform === "linux") return "shioricode";
|
|
72475
|
+
return "ShioriCode";
|
|
72476
|
+
}
|
|
72477
|
+
function defaultExistingHomeDir(platform, account) {
|
|
72478
|
+
if (account === node_os.default.userInfo().username) return node_os.default.homedir();
|
|
72479
|
+
if (platform === "darwin") return node_path.default.join("/Users", account);
|
|
72480
|
+
if (platform === "linux") return account === "root" ? "/root" : node_path.default.join("/home", account);
|
|
72481
|
+
return process.env.USERPROFILE || node_os.default.homedir();
|
|
72482
|
+
}
|
|
72483
|
+
function defaultServicePath(platform) {
|
|
72484
|
+
if (platform === "darwin") return "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
|
|
72485
|
+
if (platform === "linux") return "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
72486
|
+
return process.env.Path ?? process.env.PATH ?? "";
|
|
72487
|
+
}
|
|
72488
|
+
function validateServiceAccount(account) {
|
|
72489
|
+
if (!/^[A-Za-z_][A-Za-z0-9._-]*\$?$/.test(account)) throw new Error(`Invalid service username: ${account}`);
|
|
72490
|
+
}
|
|
72491
|
+
function validateServiceLayout(layout) {
|
|
72492
|
+
const isAbsolute = layout.platform === "win32" ? node_path.default.win32.isAbsolute : node_path.default.isAbsolute;
|
|
72493
|
+
for (const [label, value] of [
|
|
72494
|
+
["home directory", layout.homeDir],
|
|
72495
|
+
["state directory", layout.stateDir],
|
|
72496
|
+
["workspace directory", layout.workspaceDir],
|
|
72497
|
+
["service definition", layout.definitionPath],
|
|
72498
|
+
["log file", layout.logPath]
|
|
72499
|
+
]) if (!isAbsolute(value) || /[\0\r\n]/.test(value)) throw new Error(`The ${label} must be an absolute path without control characters`);
|
|
72500
|
+
if (/\0|\r|\n/.test(layout.servicePath)) throw new Error("The service PATH cannot contain control characters");
|
|
72501
|
+
if (!Number.isInteger(layout.port) || layout.port < 1 || layout.port > 65535) throw new Error(`Invalid service port: ${layout.port}`);
|
|
72502
|
+
return layout;
|
|
72503
|
+
}
|
|
72461
72504
|
function supportedPlatform(platform) {
|
|
72462
72505
|
if (platform === "linux" || platform === "darwin" || platform === "win32") return platform;
|
|
72463
72506
|
throw new Error(`ShioriCode services are not supported on ${platform} yet`);
|
|
72464
72507
|
}
|
|
72465
|
-
function serviceLayout(platform) {
|
|
72508
|
+
function serviceLayout(platform, options = {}) {
|
|
72509
|
+
const accountMode = options.accountMode ?? "dedicated";
|
|
72510
|
+
const account = options.account?.trim() || (accountMode === "current" ? invokingUsername() : defaultAccount(platform));
|
|
72511
|
+
validateServiceAccount(account);
|
|
72466
72512
|
switch (platform) {
|
|
72467
|
-
case "linux":
|
|
72468
|
-
|
|
72469
|
-
|
|
72470
|
-
stateDir: "
|
|
72471
|
-
|
|
72472
|
-
|
|
72473
|
-
|
|
72474
|
-
|
|
72475
|
-
|
|
72476
|
-
|
|
72477
|
-
|
|
72478
|
-
|
|
72479
|
-
|
|
72480
|
-
|
|
72481
|
-
|
|
72482
|
-
|
|
72483
|
-
|
|
72484
|
-
}
|
|
72513
|
+
case "linux": {
|
|
72514
|
+
const dedicatedStateDir = "/var/lib/shioricode";
|
|
72515
|
+
const homeDir = options.homeDir ?? (accountMode === "dedicated" ? dedicatedStateDir : defaultExistingHomeDir(platform, account));
|
|
72516
|
+
const stateDir = options.stateDir ?? (accountMode === "dedicated" ? dedicatedStateDir : node_path.default.join(homeDir, ".shioricode-service"));
|
|
72517
|
+
return validateServiceLayout({
|
|
72518
|
+
platform,
|
|
72519
|
+
accountMode,
|
|
72520
|
+
account,
|
|
72521
|
+
homeDir,
|
|
72522
|
+
stateDir,
|
|
72523
|
+
workspaceDir: options.workspaceDir ?? node_path.default.join(stateDir, "workspaces"),
|
|
72524
|
+
definitionPath: accountMode === "dedicated" ? "/etc/systemd/system/shioricode.service" : node_path.default.join(homeDir, ".config/systemd/user/shioricode.service"),
|
|
72525
|
+
logPath: options.logPath ?? (accountMode === "dedicated" ? "/var/log/shioricode/server.log" : node_path.default.join(stateDir, "server.log")),
|
|
72526
|
+
servicePath: options.servicePath ?? defaultServicePath(platform),
|
|
72527
|
+
serviceId: "shioricode.service",
|
|
72528
|
+
port: options.port ?? SERVICE_PORT
|
|
72529
|
+
});
|
|
72530
|
+
}
|
|
72531
|
+
case "darwin": {
|
|
72532
|
+
const dedicatedStateDir = "/Library/Application Support/ShioriCode";
|
|
72533
|
+
const homeDir = options.homeDir ?? (accountMode === "dedicated" ? dedicatedStateDir : defaultExistingHomeDir(platform, account));
|
|
72534
|
+
const stateDir = options.stateDir ?? (accountMode === "dedicated" ? dedicatedStateDir : node_path.default.join(homeDir, ".shioricode-service"));
|
|
72535
|
+
return validateServiceLayout({
|
|
72536
|
+
platform,
|
|
72537
|
+
accountMode,
|
|
72538
|
+
account,
|
|
72539
|
+
homeDir,
|
|
72540
|
+
stateDir,
|
|
72541
|
+
workspaceDir: options.workspaceDir ?? (accountMode === "dedicated" ? "/Users/Shared/ShioriCode/Workspaces" : node_path.default.join(stateDir, "workspaces")),
|
|
72542
|
+
definitionPath: accountMode === "dedicated" ? "/Library/LaunchDaemons/codes.shiori.shioricode.plist" : node_path.default.join(homeDir, "Library/LaunchAgents/codes.shiori.shioricode.plist"),
|
|
72543
|
+
logPath: options.logPath ?? (accountMode === "dedicated" ? "/Library/Logs/ShioriCode/server.log" : node_path.default.join(stateDir, "server.log")),
|
|
72544
|
+
servicePath: options.servicePath ?? defaultServicePath(platform),
|
|
72545
|
+
serviceId: "codes.shiori.shioricode",
|
|
72546
|
+
port: options.port ?? SERVICE_PORT
|
|
72547
|
+
});
|
|
72548
|
+
}
|
|
72485
72549
|
case "win32": {
|
|
72486
72550
|
const programData = process.env.ProgramData || "C:\\ProgramData";
|
|
72487
|
-
const
|
|
72488
|
-
|
|
72551
|
+
const dedicatedStateDir = node_path.default.win32.join(programData, "ShioriCode");
|
|
72552
|
+
const homeDir = options.homeDir ?? (accountMode === "dedicated" ? dedicatedStateDir : defaultExistingHomeDir(platform, account));
|
|
72553
|
+
const stateDir = options.stateDir ?? (accountMode === "dedicated" ? dedicatedStateDir : node_path.default.win32.join(homeDir, ".shioricode-service"));
|
|
72554
|
+
return validateServiceLayout({
|
|
72489
72555
|
platform,
|
|
72490
|
-
|
|
72556
|
+
accountMode,
|
|
72557
|
+
account,
|
|
72558
|
+
homeDir,
|
|
72491
72559
|
stateDir,
|
|
72492
|
-
workspaceDir: node_path.default.win32.join(stateDir, "workspaces"),
|
|
72560
|
+
workspaceDir: options.workspaceDir ?? node_path.default.win32.join(stateDir, "workspaces"),
|
|
72493
72561
|
definitionPath: node_path.default.win32.join(stateDir, "service.cmd"),
|
|
72494
|
-
logPath: node_path.default.win32.join(stateDir, "server.log"),
|
|
72495
|
-
|
|
72496
|
-
|
|
72562
|
+
logPath: options.logPath ?? node_path.default.win32.join(stateDir, "server.log"),
|
|
72563
|
+
servicePath: options.servicePath ?? defaultServicePath(platform),
|
|
72564
|
+
serviceId: "ShioriCode",
|
|
72565
|
+
port: options.port ?? SERVICE_PORT
|
|
72566
|
+
});
|
|
72497
72567
|
}
|
|
72498
72568
|
}
|
|
72499
72569
|
}
|
|
@@ -72506,20 +72576,21 @@ function xmlEscape(value) {
|
|
|
72506
72576
|
function windowsBatchQuote(value) {
|
|
72507
72577
|
return `"${value.replaceAll("\"", "\"\"")}"`;
|
|
72508
72578
|
}
|
|
72509
|
-
function serviceArguments(layout) {
|
|
72510
|
-
|
|
72579
|
+
function serviceArguments(layout, requireAuth) {
|
|
72580
|
+
const args = [
|
|
72511
72581
|
"serve",
|
|
72512
72582
|
"--mode",
|
|
72513
72583
|
"web",
|
|
72514
72584
|
"--host",
|
|
72515
72585
|
"127.0.0.1",
|
|
72516
72586
|
"--port",
|
|
72517
|
-
String(
|
|
72587
|
+
String(layout.port),
|
|
72518
72588
|
"--base-dir",
|
|
72519
72589
|
layout.stateDir,
|
|
72520
|
-
"--remote",
|
|
72521
72590
|
"--no-browser"
|
|
72522
72591
|
];
|
|
72592
|
+
if (requireAuth) args.splice(-1, 0, "--remote");
|
|
72593
|
+
return args;
|
|
72523
72594
|
}
|
|
72524
72595
|
function serviceRuntimeRoot(layout) {
|
|
72525
72596
|
return node_path.default.join(layout.stateDir, "runtime");
|
|
@@ -72532,7 +72603,6 @@ function stageServiceRuntime(deps, layout) {
|
|
|
72532
72603
|
const runtimeRoot = serviceRuntimeRoot(layout);
|
|
72533
72604
|
const runtimeDir = node_path.default.join(runtimeRoot, `${Date.now()}-${(0, node_crypto.randomBytes)(6).toString("hex")}`);
|
|
72534
72605
|
const packageTarget = node_path.default.join(runtimeDir, "package");
|
|
72535
|
-
const nodeTarget = node_path.default.join(runtimeDir, layout.platform === "win32" ? "node.exe" : "node");
|
|
72536
72606
|
node_fs.default.mkdirSync(runtimeDir, {
|
|
72537
72607
|
recursive: true,
|
|
72538
72608
|
mode: 488
|
|
@@ -72542,8 +72612,6 @@ function stageServiceRuntime(deps, layout) {
|
|
|
72542
72612
|
recursive: true,
|
|
72543
72613
|
dereference: true
|
|
72544
72614
|
});
|
|
72545
|
-
node_fs.default.copyFileSync(deps.execPath, nodeTarget, node_fs.default.constants.COPYFILE_FICLONE);
|
|
72546
|
-
if (layout.platform !== "win32") node_fs.default.chmodSync(nodeTarget, 493);
|
|
72547
72615
|
} catch (error) {
|
|
72548
72616
|
node_fs.default.rmSync(runtimeDir, {
|
|
72549
72617
|
recursive: true,
|
|
@@ -72555,7 +72623,6 @@ function stageServiceRuntime(deps, layout) {
|
|
|
72555
72623
|
runtimeDir,
|
|
72556
72624
|
dependencies: {
|
|
72557
72625
|
...deps,
|
|
72558
|
-
execPath: nodeTarget,
|
|
72559
72626
|
cliPath: node_path.default.join(packageTarget, "dist", "bin.mjs")
|
|
72560
72627
|
}
|
|
72561
72628
|
};
|
|
@@ -72580,6 +72647,14 @@ function pruneStagedServiceRuntimes(layout, activeRuntimeDir) {
|
|
|
72580
72647
|
}
|
|
72581
72648
|
}
|
|
72582
72649
|
async function protectStagedServiceRuntime(deps, layout) {
|
|
72650
|
+
if (layout.accountMode === "current") {
|
|
72651
|
+
if (layout.platform !== "win32") await deps.run("chmod", [
|
|
72652
|
+
"-R",
|
|
72653
|
+
"u+rX",
|
|
72654
|
+
serviceRuntimeRoot(layout)
|
|
72655
|
+
]);
|
|
72656
|
+
return;
|
|
72657
|
+
}
|
|
72583
72658
|
const runtimeRoot = serviceRuntimeRoot(layout);
|
|
72584
72659
|
if (layout.platform === "win32") {
|
|
72585
72660
|
await deps.run("icacls.exe", [
|
|
@@ -72605,11 +72680,14 @@ async function protectStagedServiceRuntime(deps, layout) {
|
|
|
72605
72680
|
}
|
|
72606
72681
|
function renderSystemdUnit(input) {
|
|
72607
72682
|
const { layout } = input;
|
|
72683
|
+
const hasRecoveryLogin = input.recoveryUsername !== null && input.recoveryPassword !== null;
|
|
72608
72684
|
const command = [
|
|
72609
72685
|
input.execPath,
|
|
72610
72686
|
input.cliPath,
|
|
72611
|
-
...serviceArguments(layout)
|
|
72687
|
+
...serviceArguments(layout, hasRecoveryLogin)
|
|
72612
72688
|
].map(systemdQuote).join(" ");
|
|
72689
|
+
const account = layout.accountMode === "dedicated" ? `User=${layout.account}\nGroup=${layout.account}\n` : "";
|
|
72690
|
+
const recoveryLogin = hasRecoveryLogin ? `Environment=${systemdQuote(`SHIORICODE_USERNAME=${input.recoveryUsername}`)}\nEnvironment=${systemdQuote(`SHIORICODE_PASSWORD=${input.recoveryPassword}`)}\n` : "";
|
|
72613
72691
|
return `[Unit]
|
|
72614
72692
|
Description=ShioriCode headless server
|
|
72615
72693
|
After=network-online.target
|
|
@@ -72617,45 +72695,40 @@ Wants=network-online.target
|
|
|
72617
72695
|
|
|
72618
72696
|
[Service]
|
|
72619
72697
|
Type=simple
|
|
72620
|
-
|
|
72621
|
-
|
|
72622
|
-
WorkingDirectory=${layout.workspaceDir}
|
|
72623
|
-
Environment=HOME=${layout.stateDir}
|
|
72698
|
+
${account}WorkingDirectory=${systemdQuote(layout.workspaceDir)}
|
|
72699
|
+
Environment=${systemdQuote(`HOME=${layout.homeDir}`)}
|
|
72624
72700
|
Environment=NODE_ENV=production
|
|
72625
72701
|
Environment=SHIORICODE_SERVICE=1
|
|
72626
72702
|
Environment=SHIORICODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD=false
|
|
72627
|
-
Environment
|
|
72628
|
-
|
|
72629
|
-
Environment=SHIORICODE_PASSWORD=${input.recoveryPassword}
|
|
72630
|
-
ExecStart=${command}
|
|
72703
|
+
Environment=${systemdQuote(`PATH=${layout.servicePath}`)}
|
|
72704
|
+
${recoveryLogin}ExecStart=${command}
|
|
72631
72705
|
Restart=on-failure
|
|
72632
72706
|
RestartSec=3
|
|
72633
72707
|
SuccessExitStatus=130 143
|
|
72634
72708
|
LimitNOFILE=65535
|
|
72635
|
-
StandardOutput
|
|
72636
|
-
StandardError
|
|
72709
|
+
StandardOutput=${systemdQuote(`append:${layout.logPath}`)}
|
|
72710
|
+
StandardError=${systemdQuote(`append:${layout.logPath}`)}
|
|
72637
72711
|
|
|
72638
72712
|
[Install]
|
|
72639
72713
|
WantedBy=multi-user.target
|
|
72640
72714
|
`;
|
|
72641
72715
|
}
|
|
72642
72716
|
function renderLaunchDaemon(input) {
|
|
72717
|
+
const hasRecoveryLogin = input.recoveryUsername !== null && input.recoveryPassword !== null;
|
|
72643
72718
|
const args = [
|
|
72644
72719
|
input.execPath,
|
|
72645
72720
|
input.cliPath,
|
|
72646
|
-
...serviceArguments(input.layout)
|
|
72721
|
+
...serviceArguments(input.layout, hasRecoveryLogin)
|
|
72647
72722
|
].map((value) => ` <string>${xmlEscape(value)}</string>`).join("\n");
|
|
72723
|
+
const account = input.layout.accountMode === "dedicated" ? ` <key>UserName</key>\n <string>${input.layout.account}</string>\n <key>GroupName</key>\n <string>${input.layout.account}</string>\n` : "";
|
|
72724
|
+
const recoveryLogin = hasRecoveryLogin ? ` <key>SHIORICODE_USERNAME</key><string>${xmlEscape(input.recoveryUsername)}</string>\n <key>SHIORICODE_PASSWORD</key><string>${xmlEscape(input.recoveryPassword)}</string>\n` : "";
|
|
72648
72725
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
72649
72726
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
72650
72727
|
<plist version="1.0">
|
|
72651
72728
|
<dict>
|
|
72652
72729
|
<key>Label</key>
|
|
72653
72730
|
<string>${input.layout.serviceId}</string>
|
|
72654
|
-
<key>
|
|
72655
|
-
<string>${input.layout.account}</string>
|
|
72656
|
-
<key>GroupName</key>
|
|
72657
|
-
<string>${input.layout.account}</string>
|
|
72658
|
-
<key>WorkingDirectory</key>
|
|
72731
|
+
${account} <key>WorkingDirectory</key>
|
|
72659
72732
|
<string>${xmlEscape(input.layout.workspaceDir)}</string>
|
|
72660
72733
|
<key>ProgramArguments</key>
|
|
72661
72734
|
<array>
|
|
@@ -72663,14 +72736,12 @@ ${args}
|
|
|
72663
72736
|
</array>
|
|
72664
72737
|
<key>EnvironmentVariables</key>
|
|
72665
72738
|
<dict>
|
|
72666
|
-
<key>HOME</key><string>${xmlEscape(input.layout.
|
|
72739
|
+
<key>HOME</key><string>${xmlEscape(input.layout.homeDir)}</string>
|
|
72667
72740
|
<key>NODE_ENV</key><string>production</string>
|
|
72668
72741
|
<key>SHIORICODE_SERVICE</key><string>1</string>
|
|
72669
72742
|
<key>SHIORICODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD</key><string>false</string>
|
|
72670
|
-
<key>PATH</key><string
|
|
72671
|
-
|
|
72672
|
-
<key>SHIORICODE_PASSWORD</key><string>${xmlEscape(input.recoveryPassword)}</string>
|
|
72673
|
-
</dict>
|
|
72743
|
+
<key>PATH</key><string>${xmlEscape(input.layout.servicePath)}</string>
|
|
72744
|
+
${recoveryLogin} </dict>
|
|
72674
72745
|
<key>RunAtLoad</key><true/>
|
|
72675
72746
|
<key>KeepAlive</key><true/>
|
|
72676
72747
|
<key>ThrottleInterval</key><integer>3</integer>
|
|
@@ -72681,19 +72752,20 @@ ${args}
|
|
|
72681
72752
|
`;
|
|
72682
72753
|
}
|
|
72683
72754
|
function renderWindowsServiceScript(input) {
|
|
72755
|
+
const hasRecoveryLogin = input.recoveryUsername !== null && input.recoveryPassword !== null;
|
|
72684
72756
|
const command = [
|
|
72685
72757
|
input.execPath,
|
|
72686
72758
|
input.cliPath,
|
|
72687
|
-
...serviceArguments(input.layout)
|
|
72759
|
+
...serviceArguments(input.layout, hasRecoveryLogin)
|
|
72688
72760
|
].map(windowsBatchQuote).join(" ");
|
|
72761
|
+
const recoveryLogin = hasRecoveryLogin ? `set "SHIORICODE_USERNAME=${input.recoveryUsername}"\r\nset "SHIORICODE_PASSWORD=${input.recoveryPassword}"\r\n` : "";
|
|
72689
72762
|
return `@echo off\r
|
|
72690
|
-
set "HOME=${input.layout.
|
|
72763
|
+
set "HOME=${input.layout.homeDir}"\r
|
|
72691
72764
|
set "NODE_ENV=production"\r
|
|
72692
72765
|
set "SHIORICODE_SERVICE=1"\r
|
|
72693
72766
|
set "SHIORICODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD=false"\r
|
|
72694
|
-
set "
|
|
72695
|
-
|
|
72696
|
-
cd /d ${windowsBatchQuote(input.layout.workspaceDir)}\r
|
|
72767
|
+
set "PATH=${input.layout.servicePath}"\r
|
|
72768
|
+
${recoveryLogin}cd /d ${windowsBatchQuote(input.layout.workspaceDir)}\r
|
|
72697
72769
|
${command} >> ${windowsBatchQuote(input.layout.logPath)} 2>&1\r
|
|
72698
72770
|
`;
|
|
72699
72771
|
}
|
|
@@ -72709,11 +72781,24 @@ function defaultDependencies$2() {
|
|
|
72709
72781
|
if (!cliArg) throw new Error("Could not resolve the ShioriCode executable path");
|
|
72710
72782
|
return {
|
|
72711
72783
|
platform: supportedPlatform(process.platform),
|
|
72712
|
-
execPath:
|
|
72784
|
+
execPath: stableNodeExecutable(),
|
|
72713
72785
|
cliPath: node_fs.default.realpathSync(cliArg),
|
|
72714
72786
|
run: runDefault
|
|
72715
72787
|
};
|
|
72716
72788
|
}
|
|
72789
|
+
function stableNodeExecutable() {
|
|
72790
|
+
if (process.platform === "win32") return process.execPath;
|
|
72791
|
+
const pathEntries = (process.env.PATH ?? "").split(node_path.default.delimiter);
|
|
72792
|
+
for (const entry of pathEntries) {
|
|
72793
|
+
if (!entry) continue;
|
|
72794
|
+
const candidate = node_path.default.join(entry, "node");
|
|
72795
|
+
try {
|
|
72796
|
+
node_fs.default.accessSync(candidate, node_fs.default.constants.X_OK);
|
|
72797
|
+
return candidate;
|
|
72798
|
+
} catch {}
|
|
72799
|
+
}
|
|
72800
|
+
return process.execPath;
|
|
72801
|
+
}
|
|
72717
72802
|
function requireAdministrator(platform) {
|
|
72718
72803
|
if (platform !== "win32" && typeof process.getuid === "function" && process.getuid() !== 0) throw new Error("Service installation requires administrator privileges. Re-run with sudo.");
|
|
72719
72804
|
}
|
|
@@ -72726,7 +72811,9 @@ async function commandExists$1(run, file, args) {
|
|
|
72726
72811
|
}
|
|
72727
72812
|
}
|
|
72728
72813
|
async function ensureLinuxAccount(deps, layout) {
|
|
72729
|
-
|
|
72814
|
+
const accountExists = await commandExists$1(deps.run, "id", ["-u", layout.account]);
|
|
72815
|
+
if (!accountExists && layout.accountMode === "current") throw new Error(`The requested existing service user ${layout.account} does not exist`);
|
|
72816
|
+
if (!accountExists) await deps.run("useradd", [
|
|
72730
72817
|
"--system",
|
|
72731
72818
|
"--home-dir",
|
|
72732
72819
|
layout.stateDir,
|
|
@@ -72735,6 +72822,10 @@ async function ensureLinuxAccount(deps, layout) {
|
|
|
72735
72822
|
"/usr/sbin/nologin",
|
|
72736
72823
|
layout.account
|
|
72737
72824
|
]);
|
|
72825
|
+
node_fs.default.mkdirSync(layout.stateDir, {
|
|
72826
|
+
recursive: true,
|
|
72827
|
+
mode: 488
|
|
72828
|
+
});
|
|
72738
72829
|
node_fs.default.mkdirSync(layout.workspaceDir, {
|
|
72739
72830
|
recursive: true,
|
|
72740
72831
|
mode: 488
|
|
@@ -72743,14 +72834,15 @@ async function ensureLinuxAccount(deps, layout) {
|
|
|
72743
72834
|
recursive: true,
|
|
72744
72835
|
mode: 488
|
|
72745
72836
|
});
|
|
72837
|
+
if (layout.accountMode === "current") return;
|
|
72746
72838
|
await deps.run("chown", [
|
|
72747
72839
|
"-R",
|
|
72748
|
-
|
|
72840
|
+
layout.account,
|
|
72749
72841
|
layout.stateDir
|
|
72750
72842
|
]);
|
|
72751
72843
|
await deps.run("chown", [
|
|
72752
72844
|
"-R",
|
|
72753
|
-
|
|
72845
|
+
layout.account,
|
|
72754
72846
|
node_path.default.dirname(layout.logPath)
|
|
72755
72847
|
]);
|
|
72756
72848
|
}
|
|
@@ -72785,6 +72877,22 @@ async function readMacNumericAttribute(deps, record, attribute) {
|
|
|
72785
72877
|
}
|
|
72786
72878
|
}
|
|
72787
72879
|
async function ensureMacAccount(deps, layout) {
|
|
72880
|
+
if (layout.accountMode === "current") {
|
|
72881
|
+
if (!await commandExists$1(deps.run, "id", ["-u", layout.account])) throw new Error(`The requested existing service user ${layout.account} does not exist`);
|
|
72882
|
+
node_fs.default.mkdirSync(layout.stateDir, {
|
|
72883
|
+
recursive: true,
|
|
72884
|
+
mode: 488
|
|
72885
|
+
});
|
|
72886
|
+
node_fs.default.mkdirSync(layout.workspaceDir, {
|
|
72887
|
+
recursive: true,
|
|
72888
|
+
mode: 488
|
|
72889
|
+
});
|
|
72890
|
+
node_fs.default.mkdirSync(node_path.default.dirname(layout.logPath), {
|
|
72891
|
+
recursive: true,
|
|
72892
|
+
mode: 488
|
|
72893
|
+
});
|
|
72894
|
+
return;
|
|
72895
|
+
}
|
|
72788
72896
|
const userRecord = `/Users/${layout.account}`;
|
|
72789
72897
|
const groupRecord = `/Groups/${layout.account}`;
|
|
72790
72898
|
const existingUid = await readMacNumericAttribute(deps, userRecord, "UniqueID");
|
|
@@ -72894,58 +73002,80 @@ async function ensureMacAccount(deps, layout) {
|
|
|
72894
73002
|
node_path.default.dirname(layout.logPath)
|
|
72895
73003
|
]);
|
|
72896
73004
|
}
|
|
72897
|
-
async function installLinux(deps, layout, recoveryPassword) {
|
|
73005
|
+
async function installLinux(deps, layout, recoveryUsername, recoveryPassword) {
|
|
72898
73006
|
await ensureLinuxAccount(deps, layout);
|
|
72899
73007
|
const staged = stageServiceRuntime(deps, layout);
|
|
72900
73008
|
await protectStagedServiceRuntime(deps, layout);
|
|
73009
|
+
node_fs.default.mkdirSync(node_path.default.dirname(layout.definitionPath), {
|
|
73010
|
+
recursive: true,
|
|
73011
|
+
mode: 493
|
|
73012
|
+
});
|
|
72901
73013
|
node_fs.default.writeFileSync(layout.definitionPath, renderSystemdUnit({
|
|
72902
73014
|
...staged.dependencies,
|
|
72903
73015
|
layout,
|
|
73016
|
+
recoveryUsername,
|
|
72904
73017
|
recoveryPassword
|
|
72905
73018
|
}), { mode: 384 });
|
|
72906
|
-
|
|
72907
|
-
await deps.run("systemctl", ["
|
|
72908
|
-
await deps.run("systemctl", [
|
|
73019
|
+
const systemctl = layout.accountMode === "current" ? ["--user"] : [];
|
|
73020
|
+
await deps.run("systemctl", [...systemctl, "daemon-reload"]);
|
|
73021
|
+
await deps.run("systemctl", [
|
|
73022
|
+
...systemctl,
|
|
73023
|
+
"enable",
|
|
73024
|
+
layout.serviceId
|
|
73025
|
+
]);
|
|
73026
|
+
await deps.run("systemctl", [
|
|
73027
|
+
...systemctl,
|
|
73028
|
+
"restart",
|
|
73029
|
+
layout.serviceId
|
|
73030
|
+
]);
|
|
72909
73031
|
pruneStagedServiceRuntimes(layout, staged.runtimeDir);
|
|
72910
73032
|
}
|
|
72911
|
-
async function installMac(deps, layout, recoveryPassword) {
|
|
73033
|
+
async function installMac(deps, layout, recoveryUsername, recoveryPassword) {
|
|
72912
73034
|
await ensureMacAccount(deps, layout);
|
|
72913
73035
|
const staged = stageServiceRuntime(deps, layout);
|
|
72914
73036
|
await protectStagedServiceRuntime(deps, layout);
|
|
73037
|
+
node_fs.default.mkdirSync(node_path.default.dirname(layout.definitionPath), {
|
|
73038
|
+
recursive: true,
|
|
73039
|
+
mode: 493
|
|
73040
|
+
});
|
|
72915
73041
|
node_fs.default.writeFileSync(layout.definitionPath, renderLaunchDaemon({
|
|
72916
73042
|
...staged.dependencies,
|
|
72917
73043
|
layout,
|
|
73044
|
+
recoveryUsername,
|
|
72918
73045
|
recoveryPassword
|
|
72919
73046
|
}), { mode: 384 });
|
|
73047
|
+
const domain = layout.accountMode === "dedicated" ? "system" : `gui/${invokingUid()}`;
|
|
72920
73048
|
await deps.run("launchctl", [
|
|
72921
73049
|
"bootout",
|
|
72922
|
-
|
|
73050
|
+
domain,
|
|
72923
73051
|
layout.definitionPath
|
|
72924
73052
|
]).catch(() => {});
|
|
72925
73053
|
await deps.run("launchctl", [
|
|
72926
73054
|
"bootstrap",
|
|
72927
|
-
|
|
73055
|
+
domain,
|
|
72928
73056
|
layout.definitionPath
|
|
72929
73057
|
]);
|
|
72930
|
-
await deps.run("launchctl", ["enable",
|
|
73058
|
+
await deps.run("launchctl", ["enable", `${domain}/${layout.serviceId}`]);
|
|
72931
73059
|
await deps.run("launchctl", [
|
|
72932
73060
|
"kickstart",
|
|
72933
73061
|
"-k",
|
|
72934
|
-
|
|
73062
|
+
`${domain}/${layout.serviceId}`
|
|
72935
73063
|
]);
|
|
72936
73064
|
pruneStagedServiceRuntimes(layout, staged.runtimeDir);
|
|
72937
73065
|
}
|
|
72938
|
-
async function installWindows(deps, layout, recoveryPassword) {
|
|
72939
|
-
const accountPassword = (0, node_crypto.randomBytes)(32).toString("base64url");
|
|
72940
|
-
|
|
72941
|
-
|
|
72942
|
-
"
|
|
72943
|
-
|
|
72944
|
-
|
|
72945
|
-
|
|
72946
|
-
|
|
73066
|
+
async function installWindows(deps, layout, recoveryUsername, recoveryPassword) {
|
|
73067
|
+
const accountPassword = layout.accountMode === "dedicated" ? (0, node_crypto.randomBytes)(32).toString("base64url") : null;
|
|
73068
|
+
if (accountPassword) {
|
|
73069
|
+
const ps = renderWindowsAccountScript(layout.account, accountPassword);
|
|
73070
|
+
await deps.run("powershell.exe", [
|
|
73071
|
+
"-NoProfile",
|
|
73072
|
+
"-NonInteractive",
|
|
73073
|
+
"-Command",
|
|
73074
|
+
ps
|
|
73075
|
+
]);
|
|
73076
|
+
}
|
|
72947
73077
|
node_fs.default.mkdirSync(layout.workspaceDir, { recursive: true });
|
|
72948
|
-
await deps.run("icacls.exe", [
|
|
73078
|
+
if (layout.accountMode === "dedicated") await deps.run("icacls.exe", [
|
|
72949
73079
|
layout.stateDir,
|
|
72950
73080
|
"/inheritance:r",
|
|
72951
73081
|
"/grant:r",
|
|
@@ -72958,6 +73088,7 @@ async function installWindows(deps, layout, recoveryPassword) {
|
|
|
72958
73088
|
node_fs.default.writeFileSync(layout.definitionPath, renderWindowsServiceScript({
|
|
72959
73089
|
...staged.dependencies,
|
|
72960
73090
|
layout,
|
|
73091
|
+
recoveryUsername,
|
|
72961
73092
|
recoveryPassword
|
|
72962
73093
|
}), "utf8");
|
|
72963
73094
|
await deps.run("schtasks.exe", [
|
|
@@ -72965,16 +73096,23 @@ async function installWindows(deps, layout, recoveryPassword) {
|
|
|
72965
73096
|
"/TN",
|
|
72966
73097
|
layout.serviceId
|
|
72967
73098
|
]).catch(() => {});
|
|
73099
|
+
const accountArguments = accountPassword ? [
|
|
73100
|
+
"/RU",
|
|
73101
|
+
`.\\${layout.account}`,
|
|
73102
|
+
"/RP",
|
|
73103
|
+
accountPassword
|
|
73104
|
+
] : [
|
|
73105
|
+
"/RU",
|
|
73106
|
+
layout.account,
|
|
73107
|
+
"/NP"
|
|
73108
|
+
];
|
|
72968
73109
|
await deps.run("schtasks.exe", [
|
|
72969
73110
|
"/Create",
|
|
72970
73111
|
"/TN",
|
|
72971
73112
|
layout.serviceId,
|
|
72972
73113
|
"/SC",
|
|
72973
|
-
"ONSTART",
|
|
72974
|
-
|
|
72975
|
-
`.\\${layout.account}`,
|
|
72976
|
-
"/RP",
|
|
72977
|
-
accountPassword,
|
|
73114
|
+
layout.accountMode === "dedicated" ? "ONSTART" : "ONLOGON",
|
|
73115
|
+
...accountArguments,
|
|
72978
73116
|
"/TR",
|
|
72979
73117
|
layout.definitionPath,
|
|
72980
73118
|
"/F"
|
|
@@ -72998,21 +73136,90 @@ $userList='HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Spe
|
|
|
72998
73136
|
New-Item -Path $userList -Force | Out-Null
|
|
72999
73137
|
New-ItemProperty -Path $userList -Name $name -PropertyType DWord -Value 0 -Force | Out-Null`;
|
|
73000
73138
|
}
|
|
73001
|
-
|
|
73139
|
+
function systemServiceLayoutMetadataPath(platform) {
|
|
73140
|
+
if (platform === "linux") return "/etc/shioricode/service-layout.json";
|
|
73141
|
+
if (platform === "darwin") return "/Library/Preferences/codes.shiori.shioricode.service-layout.json";
|
|
73142
|
+
const programData = process.env.ProgramData || "C:\\ProgramData";
|
|
73143
|
+
return node_path.default.win32.join(programData, "ShioriCodeService", "service-layout.json");
|
|
73144
|
+
}
|
|
73145
|
+
function serviceLayoutMetadataPath(layout) {
|
|
73146
|
+
if (layout.accountMode === "dedicated") return systemServiceLayoutMetadataPath(layout.platform);
|
|
73147
|
+
const metadataHome = defaultExistingHomeDir(layout.platform, invokingUsername());
|
|
73148
|
+
if (layout.platform === "linux") return node_path.default.join(metadataHome, ".config/shioricode/service-layout.json");
|
|
73149
|
+
if (layout.platform === "darwin") return node_path.default.join(metadataHome, "Library/Application Support/ShioriCode Service/service-layout.json");
|
|
73150
|
+
return node_path.default.win32.join(process.env.LOCALAPPDATA || node_path.default.win32.join(metadataHome, "AppData", "Local"), "ShioriCodeService", "service-layout.json");
|
|
73151
|
+
}
|
|
73152
|
+
function writeServiceLayout(layout) {
|
|
73153
|
+
const metadataPath = serviceLayoutMetadataPath(layout);
|
|
73154
|
+
node_fs.default.mkdirSync(node_path.default.dirname(metadataPath), {
|
|
73155
|
+
recursive: true,
|
|
73156
|
+
mode: 493
|
|
73157
|
+
});
|
|
73158
|
+
node_fs.default.writeFileSync(metadataPath, `${JSON.stringify({
|
|
73159
|
+
version: SERVICE_LAYOUT_VERSION,
|
|
73160
|
+
layout
|
|
73161
|
+
}, null, 2)}\n`, { mode: 384 });
|
|
73162
|
+
if (layout.accountMode === "dedicated" && layout.platform !== "win32") {
|
|
73163
|
+
node_fs.default.chownSync(metadataPath, 0, 0);
|
|
73164
|
+
node_fs.default.chmodSync(metadataPath, 384);
|
|
73165
|
+
}
|
|
73166
|
+
}
|
|
73167
|
+
function readServiceLayout(metadataPath, platform) {
|
|
73168
|
+
try {
|
|
73169
|
+
const parsed = JSON.parse(node_fs.default.readFileSync(metadataPath, "utf8"));
|
|
73170
|
+
const layout = parsed.layout;
|
|
73171
|
+
if (parsed.version !== SERVICE_LAYOUT_VERSION || layout?.platform !== platform || layout.accountMode !== "dedicated" && layout.accountMode !== "current" || typeof layout.account !== "string" || typeof layout.homeDir !== "string" || typeof layout.stateDir !== "string" || typeof layout.workspaceDir !== "string" || typeof layout.definitionPath !== "string" || typeof layout.logPath !== "string" || typeof layout.servicePath !== "string" || typeof layout.serviceId !== "string" || typeof layout.port !== "number") return null;
|
|
73172
|
+
return layout;
|
|
73173
|
+
} catch {
|
|
73174
|
+
return null;
|
|
73175
|
+
}
|
|
73176
|
+
}
|
|
73177
|
+
function readInstalledServiceLayout(platform) {
|
|
73178
|
+
const currentLayout = readServiceLayout(serviceLayoutMetadataPath(serviceLayout(platform, { accountMode: "current" })), platform);
|
|
73179
|
+
if (currentLayout && node_fs.default.existsSync(currentLayout.definitionPath)) return currentLayout;
|
|
73180
|
+
const systemLayout = readServiceLayout(systemServiceLayoutMetadataPath(platform), platform);
|
|
73181
|
+
if (systemLayout && node_fs.default.existsSync(systemLayout.definitionPath)) return systemLayout;
|
|
73182
|
+
const legacy = serviceLayout(platform);
|
|
73183
|
+
return node_fs.default.existsSync(legacy.definitionPath) ? legacy : null;
|
|
73184
|
+
}
|
|
73185
|
+
function recoveryPasswordFromOptions(options) {
|
|
73186
|
+
if (!options.recoveryPasswordFile) return {
|
|
73187
|
+
password: (0, node_crypto.randomBytes)(32).toString("base64url"),
|
|
73188
|
+
generated: true
|
|
73189
|
+
};
|
|
73190
|
+
const password = node_fs.default.readFileSync(options.recoveryPasswordFile, "utf8").replace(/\r?\n$/, "");
|
|
73191
|
+
if (!password) throw new Error("The recovery password file is empty");
|
|
73192
|
+
if (/[\0\r\n]/.test(password)) throw new Error("The recovery password file must contain exactly one password line");
|
|
73193
|
+
return {
|
|
73194
|
+
password,
|
|
73195
|
+
generated: false
|
|
73196
|
+
};
|
|
73197
|
+
}
|
|
73198
|
+
async function installService(options = {}, overrides = {}) {
|
|
73002
73199
|
const deps = {
|
|
73003
73200
|
...defaultDependencies$2(),
|
|
73004
73201
|
...overrides
|
|
73005
73202
|
};
|
|
73006
|
-
const layout = serviceLayout(deps.platform);
|
|
73007
|
-
|
|
73008
|
-
|
|
73009
|
-
if (
|
|
73010
|
-
|
|
73011
|
-
if (
|
|
73203
|
+
const layout = serviceLayout(deps.platform, options);
|
|
73204
|
+
if (layout.accountMode === "current" && layout.account !== invokingUsername()) throw new Error("Current-account services must run as the invoking OS user");
|
|
73205
|
+
if (layout.accountMode === "dedicated") requireAdministrator(deps.platform);
|
|
73206
|
+
if (options.disableRecoveryLogin && (options.recoveryUsername || options.recoveryPasswordFile)) throw new Error("--no-recovery-login cannot be combined with recovery username/password options");
|
|
73207
|
+
const recoveryUsername = options.disableRecoveryLogin ? null : options.recoveryUsername?.trim() || RECOVERY_USERNAME;
|
|
73208
|
+
if (recoveryUsername !== null && !/^[A-Za-z0-9._@-]{1,128}$/.test(recoveryUsername)) throw new Error("The recovery username contains unsupported characters");
|
|
73209
|
+
const recoveryPassword = options.disableRecoveryLogin ? {
|
|
73210
|
+
password: null,
|
|
73211
|
+
generated: false
|
|
73212
|
+
} : recoveryPasswordFromOptions(options);
|
|
73213
|
+
if (deps.platform === "win32" && recoveryPassword.password !== null && /[%"]/.test(recoveryPassword.password)) throw new Error("Windows recovery passwords cannot contain `%` or `\"`");
|
|
73214
|
+
if (deps.platform === "linux") await installLinux(deps, layout, recoveryUsername, recoveryPassword.password);
|
|
73215
|
+
if (deps.platform === "darwin") await installMac(deps, layout, recoveryUsername, recoveryPassword.password);
|
|
73216
|
+
if (deps.platform === "win32") await installWindows(deps, layout, recoveryUsername, recoveryPassword.password);
|
|
73217
|
+
writeServiceLayout(layout);
|
|
73012
73218
|
return {
|
|
73013
73219
|
layout,
|
|
73014
|
-
recoveryUsername
|
|
73015
|
-
recoveryPassword
|
|
73220
|
+
recoveryUsername,
|
|
73221
|
+
recoveryPassword: recoveryPassword.password,
|
|
73222
|
+
recoveryPasswordGenerated: recoveryPassword.generated
|
|
73016
73223
|
};
|
|
73017
73224
|
}
|
|
73018
73225
|
async function readLog(logPath) {
|
|
@@ -73028,37 +73235,47 @@ async function controlService(action, overrides = {}) {
|
|
|
73028
73235
|
...defaultDependencies$2(),
|
|
73029
73236
|
...overrides
|
|
73030
73237
|
};
|
|
73031
|
-
const layout = serviceLayout(deps.platform);
|
|
73032
|
-
requireAdministrator(deps.platform);
|
|
73238
|
+
const layout = readInstalledServiceLayout(deps.platform) ?? serviceLayout(deps.platform);
|
|
73239
|
+
if (layout.accountMode === "dedicated") requireAdministrator(deps.platform);
|
|
73033
73240
|
if (action === "logs") return await readLog(layout.logPath);
|
|
73034
73241
|
if (deps.platform === "linux") {
|
|
73242
|
+
const systemctl = layout.accountMode === "current" ? ["--user"] : [];
|
|
73035
73243
|
if (action === "uninstall") {
|
|
73036
73244
|
await deps.run("systemctl", [
|
|
73245
|
+
...systemctl,
|
|
73037
73246
|
"disable",
|
|
73038
73247
|
"--now",
|
|
73039
73248
|
layout.serviceId
|
|
73040
73249
|
]).catch(() => {});
|
|
73041
73250
|
node_fs.default.rmSync(layout.definitionPath, { force: true });
|
|
73042
|
-
await deps.run("systemctl", ["daemon-reload"]);
|
|
73251
|
+
await deps.run("systemctl", [...systemctl, "daemon-reload"]);
|
|
73252
|
+
node_fs.default.rmSync(serviceLayoutMetadataPath(layout), { force: true });
|
|
73043
73253
|
return "Removed the systemd service. ShioriCode data and the service account were preserved.";
|
|
73044
73254
|
}
|
|
73045
73255
|
if (action === "status") return (await deps.run("systemctl", [
|
|
73256
|
+
...systemctl,
|
|
73046
73257
|
"show",
|
|
73047
73258
|
layout.serviceId,
|
|
73048
73259
|
"--no-pager",
|
|
73049
73260
|
"--property=LoadState,UnitFileState,ActiveState,SubState,MainPID,ExecMainStatus"
|
|
73050
73261
|
])).stdout.trim();
|
|
73051
|
-
return (await deps.run("systemctl", [
|
|
73262
|
+
return (await deps.run("systemctl", [
|
|
73263
|
+
...systemctl,
|
|
73264
|
+
action,
|
|
73265
|
+
layout.serviceId
|
|
73266
|
+
])).stdout.trim() || `Service ${action} complete.`;
|
|
73052
73267
|
}
|
|
73053
73268
|
if (deps.platform === "darwin") {
|
|
73054
|
-
const
|
|
73269
|
+
const domain = layout.accountMode === "dedicated" ? "system" : `gui/${invokingUid()}`;
|
|
73270
|
+
const target = `${domain}/${layout.serviceId}`;
|
|
73055
73271
|
if (action === "uninstall") {
|
|
73056
73272
|
await deps.run("launchctl", [
|
|
73057
73273
|
"bootout",
|
|
73058
|
-
|
|
73274
|
+
domain,
|
|
73059
73275
|
layout.definitionPath
|
|
73060
73276
|
]).catch(() => {});
|
|
73061
73277
|
node_fs.default.rmSync(layout.definitionPath, { force: true });
|
|
73278
|
+
node_fs.default.rmSync(serviceLayoutMetadataPath(layout), { force: true });
|
|
73062
73279
|
return "Removed the launch daemon. ShioriCode data and the service account were preserved.";
|
|
73063
73280
|
}
|
|
73064
73281
|
if (action === "status") try {
|
|
@@ -73069,20 +73286,20 @@ async function controlService(action, overrides = {}) {
|
|
|
73069
73286
|
if (action === "stop") {
|
|
73070
73287
|
await deps.run("launchctl", [
|
|
73071
73288
|
"bootout",
|
|
73072
|
-
|
|
73289
|
+
domain,
|
|
73073
73290
|
layout.definitionPath
|
|
73074
73291
|
]);
|
|
73075
73292
|
return "Service stop complete.";
|
|
73076
73293
|
}
|
|
73077
73294
|
if (action === "restart") await deps.run("launchctl", [
|
|
73078
73295
|
"bootout",
|
|
73079
|
-
|
|
73296
|
+
domain,
|
|
73080
73297
|
layout.definitionPath
|
|
73081
73298
|
]).catch(() => {});
|
|
73082
73299
|
if (action === "start" || action === "restart") {
|
|
73083
73300
|
await deps.run("launchctl", [
|
|
73084
73301
|
"bootstrap",
|
|
73085
|
-
|
|
73302
|
+
domain,
|
|
73086
73303
|
layout.definitionPath
|
|
73087
73304
|
]).catch(() => {});
|
|
73088
73305
|
await deps.run("launchctl", ["enable", target]);
|
|
@@ -73106,6 +73323,7 @@ async function controlService(action, overrides = {}) {
|
|
|
73106
73323
|
layout.serviceId,
|
|
73107
73324
|
"/F"
|
|
73108
73325
|
]);
|
|
73326
|
+
node_fs.default.rmSync(serviceLayoutMetadataPath(layout), { force: true });
|
|
73109
73327
|
return "Removed the Windows background task. ShioriCode data and the service account were preserved.";
|
|
73110
73328
|
}
|
|
73111
73329
|
if (action === "status") return (await deps.run("schtasks.exe", [
|
|
@@ -73144,11 +73362,13 @@ function serviceSummary(layout = serviceLayout(supportedPlatform(process.platfor
|
|
|
73144
73362
|
return [
|
|
73145
73363
|
`Platform: ${layout.platform}`,
|
|
73146
73364
|
`Service: ${layout.serviceId}`,
|
|
73147
|
-
`Account: ${layout.account}`,
|
|
73365
|
+
`Account: ${layout.account} (${layout.accountMode})`,
|
|
73366
|
+
`Home: ${layout.homeDir}`,
|
|
73148
73367
|
`Data: ${layout.stateDir}`,
|
|
73149
73368
|
`Workspaces: ${layout.workspaceDir}`,
|
|
73150
73369
|
`Logs: ${layout.logPath}`,
|
|
73151
|
-
`
|
|
73370
|
+
`PATH: ${layout.servicePath}`,
|
|
73371
|
+
`Host: http://127.0.0.1:${layout.port}`
|
|
73152
73372
|
].join("\n");
|
|
73153
73373
|
}
|
|
73154
73374
|
const currentServicePlatform = () => supportedPlatform(node_os.default.platform());
|
|
@@ -73157,8 +73377,7 @@ function requireServiceAdministrator(platform = currentServicePlatform()) {
|
|
|
73157
73377
|
return platform;
|
|
73158
73378
|
}
|
|
73159
73379
|
function findInstalledServiceLayout() {
|
|
73160
|
-
|
|
73161
|
-
return node_fs.default.existsSync(layout.definitionPath) ? layout : null;
|
|
73380
|
+
return readInstalledServiceLayout(currentServicePlatform());
|
|
73162
73381
|
}
|
|
73163
73382
|
function installedServiceLayout() {
|
|
73164
73383
|
const layout = findInstalledServiceLayout();
|
|
@@ -73169,14 +73388,13 @@ function linkServiceStateDir(layout = installedServiceLayout()) {
|
|
|
73169
73388
|
return node_path.default.join(layout.stateDir, "userdata");
|
|
73170
73389
|
}
|
|
73171
73390
|
async function repairServiceStateOwnership(layout = installedServiceLayout()) {
|
|
73172
|
-
if (layout.platform === "win32") return;
|
|
73173
|
-
|
|
73174
|
-
await runDefault("chown", [owner, layout.stateDir]);
|
|
73391
|
+
if (layout.platform === "win32" || layout.accountMode === "current") return;
|
|
73392
|
+
await runDefault("chown", [layout.account, layout.stateDir]);
|
|
73175
73393
|
for (const entry of node_fs.default.readdirSync(layout.stateDir, { withFileTypes: true })) {
|
|
73176
73394
|
if (entry.name === "runtime") continue;
|
|
73177
73395
|
await runDefault("chown", [
|
|
73178
73396
|
"-R",
|
|
73179
|
-
|
|
73397
|
+
layout.account,
|
|
73180
73398
|
node_path.default.join(layout.stateDir, entry.name)
|
|
73181
73399
|
]);
|
|
73182
73400
|
}
|
|
@@ -73257,9 +73475,8 @@ async function waitForDeviceAuthorization(input) {
|
|
|
73257
73475
|
throw new Error("The GitHub authorization code expired");
|
|
73258
73476
|
}
|
|
73259
73477
|
function serviceLinkContext() {
|
|
73260
|
-
const platform = requireServiceAdministrator();
|
|
73261
73478
|
const layout = installedServiceLayout();
|
|
73262
|
-
if (layout.
|
|
73479
|
+
if (layout.accountMode === "dedicated") requireServiceAdministrator(layout.platform);
|
|
73263
73480
|
const store = new LinkRemoteStore({ stateDir: linkServiceStateDir(layout) });
|
|
73264
73481
|
return {
|
|
73265
73482
|
layout,
|
|
@@ -73425,18 +73642,13 @@ const PROVIDERS = [
|
|
|
73425
73642
|
credentialPaths: [".kimi"]
|
|
73426
73643
|
}
|
|
73427
73644
|
];
|
|
73428
|
-
function
|
|
73429
|
-
if (platform === "darwin") return "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
|
|
73430
|
-
if (platform === "linux") return "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
|
|
73431
|
-
return process.env.Path ?? process.env.PATH ?? "";
|
|
73432
|
-
}
|
|
73433
|
-
async function binaryVersion(binary, home) {
|
|
73645
|
+
async function binaryVersion(binary, home, configuredPath) {
|
|
73434
73646
|
try {
|
|
73435
73647
|
const result = await execFile$8(binary, ["--version"], {
|
|
73436
73648
|
env: {
|
|
73437
73649
|
...process.env,
|
|
73438
73650
|
HOME: home,
|
|
73439
|
-
PATH:
|
|
73651
|
+
PATH: configuredPath
|
|
73440
73652
|
},
|
|
73441
73653
|
timeout: 5e3,
|
|
73442
73654
|
windowsHide: true
|
|
@@ -73450,26 +73662,27 @@ function hasCredentials(home, candidates) {
|
|
|
73450
73662
|
return candidates.some((candidate) => node_fs.default.existsSync(node_path.default.join(home, candidate)));
|
|
73451
73663
|
}
|
|
73452
73664
|
function serviceAccountCommand(command) {
|
|
73453
|
-
const layout = serviceLayout(currentServicePlatform());
|
|
73665
|
+
const layout = findInstalledServiceLayout() ?? serviceLayout(currentServicePlatform());
|
|
73666
|
+
if (layout.accountMode === "current") return command;
|
|
73454
73667
|
if (layout.platform === "linux") return `sudo -u ${layout.account} -H ${command}`;
|
|
73455
73668
|
if (layout.platform === "darwin") return `sudo -u ${layout.account} -H env PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin ${command}`;
|
|
73456
73669
|
return `${command} (run it for the ${layout.account} service account)`;
|
|
73457
73670
|
}
|
|
73458
73671
|
async function providerDoctor() {
|
|
73459
|
-
const layout = serviceLayout(currentServicePlatform());
|
|
73672
|
+
const layout = findInstalledServiceLayout() ?? serviceLayout(currentServicePlatform());
|
|
73460
73673
|
const lines = [
|
|
73461
73674
|
`Service account: ${layout.account}`,
|
|
73462
|
-
`Service home: ${layout.
|
|
73675
|
+
`Service home: ${layout.homeDir}`,
|
|
73463
73676
|
""
|
|
73464
73677
|
];
|
|
73465
73678
|
for (const provider of PROVIDERS) {
|
|
73466
|
-
const version = await binaryVersion(provider.binary, layout.
|
|
73679
|
+
const version = await binaryVersion(provider.binary, layout.homeDir, layout.servicePath);
|
|
73467
73680
|
if (!version) {
|
|
73468
73681
|
lines.push(`✗ ${provider.name}: not found in the service PATH`);
|
|
73469
73682
|
lines.push(` Install: ${provider.installHint}`);
|
|
73470
73683
|
continue;
|
|
73471
73684
|
}
|
|
73472
|
-
const authenticated = hasCredentials(layout.
|
|
73685
|
+
const authenticated = hasCredentials(layout.homeDir, provider.credentialPaths);
|
|
73473
73686
|
lines.push(`✓ ${provider.name}: ${version}`);
|
|
73474
73687
|
lines.push(authenticated ? " Credentials detected in the service home" : ` Sign in: ${serviceAccountCommand(provider.authHint)}`);
|
|
73475
73688
|
}
|
|
@@ -83766,7 +83979,7 @@ function resolveTarget(baseDir, deps) {
|
|
|
83766
83979
|
}
|
|
83767
83980
|
async function withRemoteRpc(target, deps, run) {
|
|
83768
83981
|
if (!target.service) return await deps.withLocalRpc(target.baseDir, run);
|
|
83769
|
-
deps.requireAdministrator(target.service.platform);
|
|
83982
|
+
if (target.service.accountMode === "dedicated") deps.requireAdministrator(target.service.platform);
|
|
83770
83983
|
const connection = await deps.connectService(target.service.stateDir);
|
|
83771
83984
|
if (!connection) throw new Error("The ShioriCode service is installed but not reachable. Run `shioricode service start`, then retry.");
|
|
83772
83985
|
try {
|
|
@@ -216801,18 +217014,21 @@ function builtInShioriMcpServers(input) {
|
|
|
216801
217014
|
return servers.map((server) => Object.assign({}, server, { providers: [provider] }));
|
|
216802
217015
|
}
|
|
216803
217016
|
function makeBuiltInStdioMcpServerEntry(name, subcommand, env) {
|
|
216804
|
-
|
|
217017
|
+
return {
|
|
216805
217018
|
name,
|
|
216806
217019
|
transport: "stdio",
|
|
216807
217020
|
command: process.execPath,
|
|
216808
217021
|
args: [...serverEntrypointArgs(), subcommand],
|
|
216809
217022
|
enabled: true,
|
|
216810
|
-
providers: []
|
|
217023
|
+
providers: [],
|
|
217024
|
+
env: makeBuiltInStdioMcpEnvironment(env)
|
|
217025
|
+
};
|
|
217026
|
+
}
|
|
217027
|
+
function makeBuiltInStdioMcpEnvironment(env) {
|
|
217028
|
+
return {
|
|
217029
|
+
...env,
|
|
217030
|
+
ELECTRON_RUN_AS_NODE: "1"
|
|
216811
217031
|
};
|
|
216812
|
-
return env ? {
|
|
216813
|
-
...entry,
|
|
216814
|
-
env
|
|
216815
|
-
} : entry;
|
|
216816
217032
|
}
|
|
216817
217033
|
function threadGoalMcpServerEntry(input) {
|
|
216818
217034
|
return makeBuiltInStdioMcpServerEntry(THREAD_GOAL_MCP_SERVER_NAME, "thread-goal-mcp", {
|
|
@@ -219726,7 +219942,7 @@ const getTelemetryIdentifier = gen$5(function* () {
|
|
|
219726
219942
|
|
|
219727
219943
|
//#endregion
|
|
219728
219944
|
//#region package.json
|
|
219729
|
-
var version$1 = "0.5.
|
|
219945
|
+
var version$1 = "0.5.3";
|
|
219730
219946
|
|
|
219731
219947
|
//#endregion
|
|
219732
219948
|
//#region src/telemetry/Layers/AnalyticsService.ts
|
|
@@ -703212,14 +703428,42 @@ const serveCommand = make$166("serve", commandFlags).pipe(withDescription$3("Run
|
|
|
703212
703428
|
const serviceActionCommand = (action, description) => make$166(action).pipe(withDescription$3(description), withHandler(() => promise$5(async () => {
|
|
703213
703429
|
console.log(await controlService(action));
|
|
703214
703430
|
})));
|
|
703431
|
+
const serviceInstallFlags = {
|
|
703432
|
+
accountMode: choice$2("account", ["dedicated", "current"]).pipe(withDescription$4("OS account strategy: create/reuse a dedicated service user, or run as the invoking user."), withDefault$2("dedicated")),
|
|
703433
|
+
account: string$10("user").pipe(withDescription$4("Override the OS username. Dedicated mode creates it when missing; current mode requires it to exist."), optional$3),
|
|
703434
|
+
homeDir: string$10("home-dir").pipe(withDescription$4("HOME exposed to provider CLIs in the service process."), optional$3),
|
|
703435
|
+
stateDir: string$10("state-dir").pipe(withDescription$4("ShioriCode service data directory."), optional$3),
|
|
703436
|
+
workspaceDir: string$10("workspace-dir").pipe(withDescription$4("Default working directory for the service."), optional$3),
|
|
703437
|
+
logPath: string$10("log-file").pipe(withDescription$4("Log file for stdout and stderr from the background service."), optional$3),
|
|
703438
|
+
servicePath: string$10("service-path").pipe(withDescription$4("PATH used to discover provider CLIs such as codex, claude, and kimi in the service."), optional$3),
|
|
703439
|
+
port: integer$4("port").pipe(withSchema(PortSchema), withDescription$4("Loopback port for the background service."), optional$3),
|
|
703440
|
+
recoveryUsername: string$10("recovery-username").pipe(withDescription$4("Username for direct recovery login. Defaults to `recovery`."), optional$3),
|
|
703441
|
+
recoveryPasswordFile: string$10("recovery-password-file").pipe(withDescription$4("Read the direct recovery password from a local file instead of generating one. The file must not be empty."), optional$3),
|
|
703442
|
+
disableRecoveryLogin: boolean$8("no-recovery-login").pipe(withDescription$4("Disable direct username/password recovery login. ShioriCode Link remains GitHub-only."), withDefault$2(false))
|
|
703443
|
+
};
|
|
703215
703444
|
const serviceCommand = make$166("service").pipe(withDescription$3("Install and control the OS background service."), withSubcommands([
|
|
703216
|
-
make$166("install").pipe(withDescription$3("Install and start ShioriCode
|
|
703217
|
-
const result = await installService(
|
|
703445
|
+
make$166("install", serviceInstallFlags).pipe(withDescription$3("Install and start ShioriCode as a dedicated or existing OS user."), withHandler((flags) => promise$5(async () => {
|
|
703446
|
+
const result = await installService({
|
|
703447
|
+
accountMode: flags.accountMode,
|
|
703448
|
+
account: getOrUndefined$3(flags.account),
|
|
703449
|
+
homeDir: getOrUndefined$3(flags.homeDir),
|
|
703450
|
+
stateDir: getOrUndefined$3(flags.stateDir),
|
|
703451
|
+
workspaceDir: getOrUndefined$3(flags.workspaceDir),
|
|
703452
|
+
logPath: getOrUndefined$3(flags.logPath),
|
|
703453
|
+
servicePath: getOrUndefined$3(flags.servicePath),
|
|
703454
|
+
port: getOrUndefined$3(flags.port),
|
|
703455
|
+
recoveryUsername: getOrUndefined$3(flags.recoveryUsername),
|
|
703456
|
+
recoveryPasswordFile: getOrUndefined$3(flags.recoveryPasswordFile),
|
|
703457
|
+
disableRecoveryLogin: flags.disableRecoveryLogin
|
|
703458
|
+
});
|
|
703218
703459
|
console.log("ShioriCode service installed and started.\n");
|
|
703219
703460
|
console.log(serviceSummary(result.layout));
|
|
703220
|
-
console.log("\nLocal recovery
|
|
703221
|
-
console.log(
|
|
703222
|
-
|
|
703461
|
+
console.log("\nLocal recovery login:");
|
|
703462
|
+
if (result.recoveryUsername === null || result.recoveryPassword === null) console.log("Disabled. Hosted access uses GitHub through ShioriCode Link.");
|
|
703463
|
+
else {
|
|
703464
|
+
console.log(`Username: ${result.recoveryUsername}`);
|
|
703465
|
+
console.log(result.recoveryPasswordGenerated ? `Generated password: ${result.recoveryPassword}\nStore it securely; it is shown once.` : "Password: loaded from --recovery-password-file (not echoed)");
|
|
703466
|
+
}
|
|
703223
703467
|
console.log("\nNext: shioricode link connect");
|
|
703224
703468
|
}))),
|
|
703225
703469
|
serviceActionCommand("start", "Start the ShioriCode service."),
|