@misterhuydo/sentinel 1.0.59 → 1.0.60
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/.cairn/minify-map.json
CHANGED
package/.cairn/session.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"message": "Auto-checkpoint at 2026-03-22T14:
|
|
3
|
-
"checkpoint_at": "2026-03-22T14:
|
|
2
|
+
"message": "Auto-checkpoint at 2026-03-22T14:43:35.624Z",
|
|
3
|
+
"checkpoint_at": "2026-03-22T14:43:35.625Z",
|
|
4
4
|
"active_files": [],
|
|
5
5
|
"notes": [],
|
|
6
6
|
"mtime_snapshot": {}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs-extra');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const { execSync, spawnSync } = require('child_process');
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
const ok = msg => console.log(chalk.green(' ✔'), msg);
|
|
8
|
+
const info = msg => console.log(chalk.cyan(' →'), msg);
|
|
9
|
+
const warn = msg => console.log(chalk.yellow(' ⚠'), msg);
|
|
10
|
+
module.exports = async function upgrade() {
|
|
11
|
+
const { version: current } = require('../package.json');
|
|
12
|
+
const defaultWorkspace = path.join(os.homedir(), 'sentinel');
|
|
13
|
+
const codeDir = path.join(defaultWorkspace, 'code');
|
|
14
|
+
if (!fs.existsSync(codeDir)) {
|
|
15
|
+
console.error(chalk.red(' ✖ Sentinel code directory not found at ' + codeDir));
|
|
16
|
+
console.error(' Run: sentinel init');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
info(`Current version: ${current}`);
|
|
20
|
+
info('Installing latest @misterhuydo/sentinel...');
|
|
21
|
+
const install = spawnSync('npm', ['install', '-g', '@misterhuydo/sentinel@latest'], { stdio: 'inherit' });
|
|
22
|
+
if (install.status !== 0) {
|
|
23
|
+
console.error(chalk.red(' ✖ npm install failed'));
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
const npmRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
|
|
27
|
+
const pkgDir = path.join(npmRoot, '@misterhuydo', 'sentinel');
|
|
28
|
+
const src = path.join(pkgDir, 'python');
|
|
29
|
+
if (!fs.existsSync(src)) {
|
|
30
|
+
console.error(chalk.red(' ✖ Bundled Python source not found in installed package'));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
info('Deploying Python source...');
|
|
34
|
+
fs.copySync(src, codeDir, { overwrite: true });
|
|
35
|
+
const scriptsDir = path.join(codeDir, 'scripts');
|
|
36
|
+
if (fs.existsSync(scriptsDir)) {
|
|
37
|
+
const shFiles = fs.readdirSync(scriptsDir)
|
|
38
|
+
.filter(f => f.endsWith('.sh'))
|
|
39
|
+
.map(f => path.join(scriptsDir, f));
|
|
40
|
+
if (shFiles.length) spawnSync('chmod', ['+x', ...shFiles], { stdio: 'inherit' });
|
|
41
|
+
}
|
|
42
|
+
ok('Python source updated');
|
|
43
|
+
const { version: latest } = require(path.join(pkgDir, 'package.json'));
|
|
44
|
+
ok(`Upgraded: ${current} → ${latest}`);
|
|
45
|
+
const startAll = path.join(defaultWorkspace, 'startAll.sh');
|
|
46
|
+
const stopAll = path.join(defaultWorkspace, 'stopAll.sh');
|
|
47
|
+
if (fs.existsSync(stopAll) && fs.existsSync(startAll)) {
|
|
48
|
+
info('Restarting Sentinel...');
|
|
49
|
+
spawnSync('bash', [stopAll], { stdio: 'inherit' });
|
|
50
|
+
spawnSync('bash', [startAll], { stdio: 'inherit' });
|
|
51
|
+
ok('Sentinel restarted');
|
|
52
|
+
} else {
|
|
53
|
+
warn('No startAll.sh found — restart manually');
|
|
54
|
+
}
|
|
55
|
+
};
|
package/package.json
CHANGED
|
@@ -875,70 +875,36 @@ async def _run_tool(name: str, inputs: dict, cfg_loader, store, slack_client=Non
|
|
|
875
875
|
|
|
876
876
|
if name == "upgrade_sentinel":
|
|
877
877
|
import threading
|
|
878
|
-
import signal as _sig
|
|
879
|
-
|
|
880
|
-
code_dir = Path(__file__).resolve().parent.parent # sentinel repo root
|
|
881
|
-
project_dir = Path(".").resolve()
|
|
882
|
-
steps: list[dict] = []
|
|
883
|
-
|
|
884
|
-
# Step 1: git pull the sentinel agent code
|
|
885
|
-
pull = _git_pull(code_dir)
|
|
886
|
-
steps.append({"step": "git_pull", **pull})
|
|
887
|
-
already_latest = "already up to date" in pull.get("detail", "").lower()
|
|
888
|
-
|
|
889
|
-
if pull["status"] == "error":
|
|
890
|
-
return json.dumps({"status": "error", "steps": steps,
|
|
891
|
-
"note": "git pull failed — check network / SSH key"})
|
|
892
|
-
|
|
893
|
-
# Step 2: pip install (update Python deps)
|
|
894
|
-
venv_pip = code_dir / ".venv" / "bin" / "pip"
|
|
895
|
-
pip_cmd = str(venv_pip) if venv_pip.exists() else "pip3"
|
|
896
|
-
req_file = code_dir / "requirements.txt"
|
|
897
|
-
if req_file.exists():
|
|
898
|
-
try:
|
|
899
|
-
r = subprocess.run(
|
|
900
|
-
[pip_cmd, "install", "-q", "-r", str(req_file)],
|
|
901
|
-
capture_output=True, text=True, timeout=120,
|
|
902
|
-
)
|
|
903
|
-
steps.append({
|
|
904
|
-
"step": "pip_install",
|
|
905
|
-
"status": "ok" if r.returncode == 0 else "warn",
|
|
906
|
-
"detail": (r.stderr or "").strip()[:200],
|
|
907
|
-
})
|
|
908
|
-
except Exception as e:
|
|
909
|
-
steps.append({"step": "pip_install", "status": "warn", "detail": str(e)})
|
|
910
878
|
|
|
911
|
-
|
|
879
|
+
# Sentinel is installed via npm — use `sentinel upgrade` which handles
|
|
880
|
+
# npm install + Python bundle copy + restart via stopAll/startAll.
|
|
881
|
+
# Run it in the background after a short delay so the Slack reply is
|
|
882
|
+
# sent before the process is replaced.
|
|
883
|
+
try:
|
|
884
|
+
r = subprocess.run(
|
|
885
|
+
["sentinel", "--version"],
|
|
886
|
+
capture_output=True, text=True, timeout=10,
|
|
887
|
+
)
|
|
888
|
+
sentinel_bin_ok = r.returncode == 0
|
|
889
|
+
except Exception:
|
|
890
|
+
sentinel_bin_ok = False
|
|
891
|
+
|
|
892
|
+
if not sentinel_bin_ok:
|
|
912
893
|
return json.dumps({
|
|
913
|
-
"status": "
|
|
914
|
-
"
|
|
915
|
-
"note": "Sentinel is already up to date. No restart needed.",
|
|
894
|
+
"status": "error",
|
|
895
|
+
"note": "`sentinel` CLI not found. Run: npm install -g @misterhuydo/sentinel",
|
|
916
896
|
})
|
|
917
897
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
def _restart_scripts():
|
|
923
|
-
import time; time.sleep(10)
|
|
924
|
-
subprocess.Popen(
|
|
925
|
-
f"bash {stop_sh} && sleep 2 && bash {start_sh}",
|
|
926
|
-
shell=True,
|
|
927
|
-
)
|
|
928
|
-
threading.Thread(target=_restart_scripts, daemon=True).start()
|
|
929
|
-
restart_method = "stop.sh + start.sh"
|
|
930
|
-
else:
|
|
931
|
-
# SIGTERM self — systemd (Restart=always) will bring it back up
|
|
932
|
-
# 10s delay gives Claude time to generate + post the reply before we die
|
|
933
|
-
threading.Timer(10.0, lambda: os.kill(os.getpid(), _sig.SIGTERM)).start()
|
|
934
|
-
restart_method = "SIGTERM → systemd restart"
|
|
898
|
+
def _do_upgrade():
|
|
899
|
+
import time
|
|
900
|
+
time.sleep(10) # give Slack time to post the reply
|
|
901
|
+
subprocess.Popen(["sentinel", "upgrade"], close_fds=True)
|
|
935
902
|
|
|
936
|
-
|
|
937
|
-
logger.info("Boss: upgrade_sentinel
|
|
903
|
+
threading.Thread(target=_do_upgrade, daemon=True).start()
|
|
904
|
+
logger.info("Boss: upgrade_sentinel scheduled via `sentinel upgrade`")
|
|
938
905
|
return json.dumps({
|
|
939
906
|
"status": "ok",
|
|
940
|
-
"
|
|
941
|
-
"note": "Upgrade complete. Sentinel is restarting — give it a few seconds then I'll be back.",
|
|
907
|
+
"note": "Upgrade started — pulling latest version via npm and restarting. Give me ~30 seconds then I'll be back.",
|
|
942
908
|
})
|
|
943
909
|
|
|
944
910
|
return json.dumps({"error": f"unknown tool: {name}"})
|