clavarium 0.1.3 → 0.1.5

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/deploy/doctor.mjs CHANGED
@@ -213,6 +213,7 @@ Description=Clavarium - the certificate, every 20 minutes
213
213
 
214
214
  [Timer]
215
215
  OnBootSec=10min
216
+ OnActiveSec=2min
216
217
  OnUnitActiveSec=20min
217
218
 
218
219
  [Install]
package/deploy/install.sh CHANGED
@@ -705,6 +705,16 @@ TUNNEL
705
705
  systemctl daemon-reload
706
706
  systemctl enable --quiet clavarium-tunnel.service
707
707
  systemctl restart clavarium-tunnel.service
708
+ # Caddy asked Let's Encrypt as it started, BEFORE the tunnel was up: it could not
709
+ # be reached, and fell back to a certificate of its own. Asked again once the
710
+ # tunnel holds (ExitOnForwardFailure: an ssh still running after 10 s has its forwards).
711
+ if [ "$RELAY_INSTALLED" = "yes" ]; then
712
+ sleep 10
713
+ if systemctl is-active --quiet clavarium-tunnel.service; then
714
+ rm -rf -- "/var/lib/caddy/caddy/certificates/local/$DOMAIN"
715
+ systemctl restart caddy.service
716
+ fi
717
+ fi
708
718
  TUNNEL_KEY="$(cat /var/lib/clavarium-tunnel/key.pub)"
709
719
  RELAY_PRINT="$(ssh-keygen -l -f /var/lib/clavarium-tunnel/known_hosts | cut -d' ' -f2 | head -1)"
710
720
  fi
@@ -595,7 +595,11 @@ async function main(argv) {
595
595
  switch (verb) {
596
596
  case 'check': await u.check().catch(() => {}); return print(u.about());
597
597
  case 'status': return print(u.about());
598
- case 'run': { const r = await u.runOnce(); console.log(typeof r === 'string' ? r : 'done'); return; }
598
+ case 'run': {
599
+ /* What this release sets up beside itself (the certificate timer), at its first turn: the
600
+ update that brought it ran the PREVIOUS release's code. Idempotent; never stops the turn. */
601
+ try { const [{ installWatch }, { realSys }] = await Promise.all([import('./doctor.mjs'), import('./online.mjs')]); if (await installWatch(realSys())) console.error('updater: the certificate timer set up'); } catch (error) { console.error(`updater: the certificate timer could not be set up: ${error.message}`); }
602
+ const r = await u.runOnce(); console.log(typeof r === 'string' ? r : 'done'); return; }
599
603
  case 'set': if (rest.length !== 2) throw new Refused('set <mode|channel|window|port> <value>'); return print(u.set(rest[0], rest[1]));
600
604
  case 'prepare': { const r = await u.prepare({ version: value('--version'), fromDir: value('--from-dir') }); console.log(r.id); return; }
601
605
  case 'switch': if (!VERSION.test(rest[0] ?? '') && !LOCAL.test(rest[0] ?? '')) throw new Refused('switch <release>'); u.switchTo(rest[0]); return;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "clavarium",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "clavarium",
9
- "version": "0.1.3",
9
+ "version": "0.1.5",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@xterm/addon-fit": "^0.11.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clavarium",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "A conversation is a VM with a terminal in it. Everything else is a folder.",
@@ -9,6 +9,7 @@
9
9
  import { isConversationName } from './names.mjs';
10
10
  import { attachCommand, SOCKET } from './tmux.mjs';
11
11
  import { WORK, VM_USER, SHARING_STEP } from './vm.mjs';
12
+ import { resumeOrFresh } from './tools.mjs';
12
13
 
13
14
  export const SESSION = 'main';
14
15
  export const STOP_DELAY_MS = 60_000;
@@ -424,7 +425,7 @@ export class Conversations {
424
425
  first: added at EVERY start, a resume included (a tool does not
425
426
  keep it from its last session). */
426
427
  const rights = tool.rights ? (c.askFirst === true ? tool.rights.ask : tool.rights.full) : [];
427
- return [...(resume ? tool.resume : tool.command), ...rights];
428
+ return resume ? resumeOrFresh([...tool.resume, ...rights], [...tool.command, ...rights]) : [...tool.command, ...rights];
428
429
  }
429
430
 
430
431
  /* Whether its tool asks before acting (true), or acts without asking in
package/server/tools.mjs CHANGED
@@ -107,3 +107,16 @@ export function readTools(text) {
107
107
  export function loadTools(path = new URL('../config/tools.json', import.meta.url)) {
108
108
  return readTools(readFileSync(path, 'utf8'));
109
109
  }
110
+
111
+ /* TAKING UP ITS LAST SESSION, OR A NEW ONE: a tool told to resume where it has
112
+ no session of its own (never spoken to, its session files gone) may just say
113
+ so and stop ("No conversation found"), leaving a dead terminal. If the resume
114
+ fails within RESUME_GRACE_S, the tool starts fresh, in the same terminal. A
115
+ tool that ran and is quit stays quit. One argument vector, for tmux. */
116
+ export const RESUME_GRACE_S = 20;
117
+ const shq = (a) => `'${String(a).replace(/'/g, `'\\''`)}'`;
118
+ export function resumeOrFresh(resume, fresh) {
119
+ const script = `t=$(date +%s); ${resume.map(shq).join(' ')}; c=$?; `
120
+ + `if [ "$c" -ne 0 ] && [ $(( $(date +%s) - t )) -lt ${RESUME_GRACE_S} ]; then echo; echo 'No session to take up here: a new one starts.'; exec ${fresh.map(shq).join(' ')}; fi; exit "$c"`;
121
+ return ['sh', '-c', script];
122
+ }