@volter/supercode-teams 0.2.82 → 0.2.84
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/connector/index.mjs +12 -1
- package/package.json +1 -1
- package/popup-terminals.mjs +11 -8
package/connector/index.mjs
CHANGED
|
@@ -262,7 +262,7 @@ export class TeamsConnector {
|
|
|
262
262
|
// syncing. An error of the connection itself (the outbox, authentication, the server, a stop) still ends
|
|
263
263
|
// the pass. The session keeps its native binding either way, so it can still be attached to.
|
|
264
264
|
let captured = true;
|
|
265
|
-
if (this.sessionChanged(options)) try { await this.capture(options); } catch (error) {
|
|
265
|
+
if (this.sessionChanged(options) && !this.predatesWindow(options)) try { await this.capture(options); } catch (error) {
|
|
266
266
|
if (connectionError(error) || this.abort.signal.aborted) throw error;
|
|
267
267
|
captured = false; this.noteSessionProblem(options, error);
|
|
268
268
|
process.stderr.write(`supercode teams: ${harness} session ${nativeSessionId} not synced: ${error.message}\n`);
|
|
@@ -278,6 +278,17 @@ export class TeamsConnector {
|
|
|
278
278
|
this.pruneNativeCache(discovered);
|
|
279
279
|
this.rotateFollowers(followCandidates);
|
|
280
280
|
}
|
|
281
|
+
// A session never published under a rule that keeps back history recorded before a time (a `since` window, or a
|
|
282
|
+
// `none` rule's capture_after), whose native file was last written before that time, holds only history the rule
|
|
283
|
+
// keeps back: loading it (a 228 MB transcript is gigabytes in the harness process and here) would publish nothing.
|
|
284
|
+
predatesWindow({locator,configuration,ruleId,ruleRevision,harness,nativeSessionId}){
|
|
285
|
+
if(this.state.origins[`${harness}:${nativeSessionId}`])return false;
|
|
286
|
+
const rule=configuration?.rules?.find(item=>item.id===ruleId&&item.revision===ruleRevision&&item.state==='active');if(!rule)return false;
|
|
287
|
+
const backfill=typeof rule.backfill==='string'?{mode:rule.backfill}:rule.backfill??{mode:'all'};
|
|
288
|
+
const keptBefore=backfill.mode==='since'?backfill.since:backfill.mode==='none'?rule.capture_after:null;
|
|
289
|
+
if(!Number.isSafeInteger(keptBefore)||locator?.storage?.kind!=='file')return false;
|
|
290
|
+
try{return statSync(realpathSync(locator.storage.path)).mtimeMs<keptBefore;}catch{return false;}
|
|
291
|
+
}
|
|
281
292
|
// When a session was last active: its descriptor's updated_at_ms, else its native file's modification time.
|
|
282
293
|
sessionActivity({locator,descriptor}){
|
|
283
294
|
let activity=Number.isSafeInteger(descriptor?.updated_at_ms)?descriptor.updated_at_ms:null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/supercode-teams",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.84",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A machine daemon serving this machine's doors, and a local or remote Teams server for shared session discovery, OpenTelemetry ingestion and access to enrolled machines.",
|
|
6
6
|
"license": "MIT",
|
package/popup-terminals.mjs
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
// daemon's ConPTY host on Windows, holds it); the pane ending ends the client, and the terminal closes the window as
|
|
5
5
|
// its command exits. Adapters are tried in rank order; SUPERCODE_POPUP_TERMINAL names one (or `none`).
|
|
6
6
|
import { spawn, spawnSync } from 'node:child_process';
|
|
7
|
-
import { chmodSync, existsSync, readdirSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { chmodSync, existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
8
8
|
import { homedir, tmpdir } from 'node:os';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
|
-
import { randomBytes } from 'node:crypto';
|
|
10
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
11
11
|
import { weztermConfigFile } from './terminal-look.mjs';
|
|
12
12
|
|
|
13
13
|
const onPath = (name) => {
|
|
@@ -31,11 +31,12 @@ function selfDeletingScript(argv, extension) {
|
|
|
31
31
|
// running process is on screen in about 0.3 s, where a process started per window took 0.7 to 2 s (measured on macOS
|
|
32
32
|
// 26 with WezTerm 20240203). The process is known by its class; it listens on ~/.local/share/wezterm/gui-sock-<pid>.
|
|
33
33
|
// A window goes into it with `wezterm cli spawn --new-window`, and when there is none, or the spawn fails, the window
|
|
34
|
-
// starts it. The fallback runs in the launched shell, so the daemon never waits on WezTerm.
|
|
34
|
+
// starts it. The fallback runs in the launched shell, so the daemon never waits on WezTerm. The class carries the
|
|
35
|
+
// config's content: WezTerm does not reload it (terminal-look.mjs), so a process holding an older look is never reused.
|
|
35
36
|
const WEZTERM_CLASS = 'dev.volter.supercode';
|
|
36
37
|
|
|
37
|
-
/** The socket of a running supercode WezTerm process
|
|
38
|
-
function weztermSocket() {
|
|
38
|
+
/** The socket of a running supercode WezTerm process of class `cls`, or null. */
|
|
39
|
+
function weztermSocket(cls) {
|
|
39
40
|
const dir = join(homedir(), '.local', 'share', 'wezterm');
|
|
40
41
|
let names;
|
|
41
42
|
try { names = readdirSync(dir); } catch { return null; }
|
|
@@ -44,15 +45,17 @@ function weztermSocket() {
|
|
|
44
45
|
if (!pid) continue;
|
|
45
46
|
try { process.kill(pid, 0); } catch { continue; }
|
|
46
47
|
const command = spawnSync('ps', ['-p', String(pid), '-o', 'command='], { encoding: 'utf8', timeout: 2_000 }).stdout ?? '';
|
|
47
|
-
if (command.includes(`--class ${
|
|
48
|
+
if (command.includes(`--class ${cls} `)) return join(dir, name);
|
|
48
49
|
}
|
|
49
50
|
return null;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
/** WezTerm's launch: a window in supercode's running WezTerm, else a new one with supercode's look (terminal-look.mjs). */
|
|
53
54
|
function weztermLaunch(program, argv) {
|
|
54
|
-
const
|
|
55
|
-
const
|
|
55
|
+
const config = weztermConfigFile();
|
|
56
|
+
const cls = `${WEZTERM_CLASS}.${createHash('sha256').update(readFileSync(config)).digest('hex').slice(0, 12)}`;
|
|
57
|
+
const start = [program, '--config-file', config, 'start', '--always-new-process', '--class', cls, '--', ...argv];
|
|
58
|
+
const socket = process.platform === 'win32' ? null : weztermSocket(cls);
|
|
56
59
|
if (!socket) return [start[0], start.slice(1)];
|
|
57
60
|
const quote = (arg) => `'${String(arg).replaceAll("'", `'"'"'`)}'`;
|
|
58
61
|
const spawnWindow = [program, 'cli', '--no-auto-start', 'spawn', '--new-window', '--', ...argv].map(quote).join(' ');
|