@sickr/cli 0.9.8 → 0.9.10

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/recorder.js CHANGED
@@ -93,7 +93,8 @@ export function mapEvent(cc, now = new Date(), ctx = {}) {
93
93
  const rawSession = String(cc.session_id ?? '');
94
94
  const session = rawSession ? rawSession.slice(0, 12) : undefined;
95
95
  const agent = ctx.agent;
96
- const base = { at, agent, session };
96
+ const runner = process.env.SICKR_RUN_INSTANCE ? process.env.SICKR_RUN_INSTANCE.slice(0, 36) : undefined;
97
+ const base = { at, agent, session, runner };
97
98
  switch (name) {
98
99
  case 'SessionStart':
99
100
  return { kind: 'start', label: 'Session', detail: redact(String(cc.cwd ?? '')), ...base };
package/dist/run.js CHANGED
@@ -23,6 +23,7 @@
23
23
  import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync, readdirSync, statSync, openSync, readSync, closeSync, unlinkSync } from 'node:fs';
24
24
  import { homedir } from 'node:os';
25
25
  import { join } from 'node:path';
26
+ import { randomUUID } from 'node:crypto';
26
27
  import { execFileSync } from 'node:child_process';
27
28
  import { setTimeout as sleep } from 'node:timers/promises';
28
29
  import { readCredentials } from './auth.js';
@@ -111,6 +112,31 @@ function appendInbox(urlid, text, at) {
111
112
  writeFileSync(file, `# steer inbox — ${urlid}\n\n`);
112
113
  appendFileSync(file, `\n## ${at}\n\n${text}\n`);
113
114
  }
115
+ function normTarget(s) {
116
+ return String(s ?? '').trim().toLowerCase();
117
+ }
118
+ export function steerMatchesRunner(msg, identity) {
119
+ if (msg.targetRunner)
120
+ return msg.targetRunner === identity.runner;
121
+ if (msg.targetSession)
122
+ return identity.sessions.has(msg.targetSession);
123
+ if (msg.targetAgent)
124
+ return normTarget(msg.targetAgent) === normTarget(identity.agent);
125
+ return true;
126
+ }
127
+ export function normalizeRunEventForRunner(event, identity) {
128
+ if (event.runner && event.runner !== identity.runner)
129
+ return null;
130
+ if (!event.runner && event.agent && normTarget(event.agent) !== normTarget(identity.agent))
131
+ return null;
132
+ if (!event.agent)
133
+ event.agent = identity.agent;
134
+ if (!event.runner)
135
+ event.runner = identity.runner;
136
+ if (event.session)
137
+ identity.sessions.add(event.session);
138
+ return event;
139
+ }
114
140
  export function decideSteer(msg, defaultMode = 'pty') {
115
141
  const text = String(msg.text ?? '');
116
142
  if (!text)
@@ -282,6 +308,10 @@ export async function startRun(opts) {
282
308
  // browser /r/<urlid> stays empty until events flow.
283
309
  ensureRecordingHooks(opts.agent);
284
310
  const agentBin = resolveAgent(opts.agent);
311
+ const provider = providerForAgent(opts.agent);
312
+ const agentLabel = provider ? PROVIDERS[provider].recordLabel : opts.agent;
313
+ const runnerId = randomUUID();
314
+ const runnerIdentity = { agent: agentLabel, runner: runnerId, sessions: new Set() };
285
315
  const cols = process.stdout.columns ?? 80;
286
316
  const rows = process.stdout.rows ?? 24;
287
317
  // mode=auto (default) injects the agent's "no prompt / full perms" flag
@@ -307,7 +337,7 @@ export async function startRun(opts) {
307
337
  name: 'xterm-256color',
308
338
  cols, rows,
309
339
  cwd: process.cwd(),
310
- env: process.env,
340
+ env: { ...process.env, SICKR_RUN_INSTANCE: runnerId, SICKR_RUN_AGENT: agentLabel },
311
341
  });
312
342
  // Wire stdio: parent stdin -> pty; pty -> parent stdout.
313
343
  if (process.stdin.isTTY)
@@ -379,7 +409,11 @@ export async function startRun(opts) {
379
409
  let opened = false;
380
410
  ws.addEventListener('open', () => {
381
411
  opened = true;
382
- tailTimer = setInterval(() => pumpNewLines(ws, offsets), 500);
412
+ try {
413
+ ws.send(JSON.stringify({ kind: 'hello', agent: runnerIdentity.agent, runner: runnerIdentity.runner }));
414
+ }
415
+ catch { /* reconnect loop handles failures */ }
416
+ tailTimer = setInterval(() => pumpNewLines(ws, offsets, runnerIdentity), 500);
383
417
  });
384
418
  ws.addEventListener('message', (ev) => {
385
419
  const raw = decodeWsPayload(ev.data);
@@ -393,6 +427,11 @@ export async function startRun(opts) {
393
427
  return;
394
428
  }
395
429
  if (m.kind === 'steer' && m.text) {
430
+ if (!steerMatchesRunner(m, runnerIdentity)) {
431
+ if (opts.verbose)
432
+ process.stderr.write(`sickr: ignored steer for another agent/session\n`);
433
+ return;
434
+ }
396
435
  const decision = decideSteer(m);
397
436
  if (decision.target === 'pty' && decision.bytes != null) {
398
437
  // Submit-fix (2026-06-01): Claude Code's TUI treats a burst of
@@ -459,7 +498,7 @@ async function loadWsShim() {
459
498
  throw new Error('`ws` is unavailable. It ships as an optional dependency of @sickr/cli; if it failed to install, try: `npm install -g ws`.');
460
499
  }
461
500
  }
462
- function pumpNewLines(ws, offsets) {
501
+ function pumpNewLines(ws, offsets, identity) {
463
502
  const dir = runsDir();
464
503
  if (!existsSync(dir))
465
504
  return;
@@ -483,7 +522,9 @@ function pumpNewLines(ws, offsets) {
483
522
  for (const line of result.lines) {
484
523
  for (const fragment of splitJsonObjects(line)) {
485
524
  try {
486
- const event = JSON.parse(fragment);
525
+ const event = normalizeRunEventForRunner(JSON.parse(fragment), identity);
526
+ if (!event)
527
+ continue;
487
528
  ws.send(JSON.stringify({ kind: 'event', event }));
488
529
  }
489
530
  catch { /* skip malformed */ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sickr/cli",
3
- "version": "0.9.8",
3
+ "version": "0.9.10",
4
4
  "type": "module",
5
5
  "description": "npx @sickr/cli - replay, live look, and workflow orchestration for AI coding agents.",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "access": "public"
15
15
  },
16
16
  "scripts": {
17
- "build": "tsc",
17
+ "build": "node --max-old-space-size=4096 ./node_modules/typescript/bin/tsc",
18
18
  "test": "vitest run",
19
19
  "dev": "tsc -w",
20
20
  "prepublishOnly": "npm run build && npm test && node scripts/pre-publish-check.mjs"