@sickr/cli 0.9.6 → 0.9.7

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.
Files changed (3) hide show
  1. package/dist/cli.js +87 -98
  2. package/dist/run.js +23 -2
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -51,113 +51,72 @@ export function buildWorkflowInvocation(rest, command = 'uvx') {
51
51
  }
52
52
  return { command, args: rest };
53
53
  }
54
- export const HELP = `SICKR Replay audit & replay what your AI coding agent did.
54
+ export const HELP = `sickrrecord, replay, and remote-control your AI coding agents.
55
55
 
56
- Records your Claude Code or Codex session (prompts, edits, commands) to a local,
57
- redacted timeline you can replay — and optionally share as a public link.
56
+ Usage: npx @sickr/cli <command> [options]
58
57
 
59
- Why: a durable record of every agent action a dashcam for your coding agent.
60
- If your agent (Claude or Codex) loses context or can't reload a past chat, the
61
- replay log helps you and it recall exactly what was just done.
58
+ REPLAY (free) local recording of every prompt, edit and command.
59
+ replay Install Claude + Codex recording hooks. Use the agents
60
+ as normala redacted timeline is captured to
61
+ ~/.sickr/runs.
62
+ replay open [id] Render the newest run (or a specific id) as a local
63
+ HTML timeline. Combine across agents with --today,
64
+ --since <2h|30m|1d>, or --all (+ --claude / --codex).
65
+ replay share [id] Publish a redacted run to sickr.ai/r/<id> (asks first).
66
+ Add --yes to skip the prompt; --open to open after.
67
+ Or combine a window: --today / --since <dur> / --all.
68
+ Anon links live 24h; signed-in links live 7 days.
69
+ replay list List recorded runs, newest first (+ --claude/--codex).
70
+ replay stop Remove sickr hooks from this project (keeps runs).
71
+ replay clear Delete all local runs in ~/.sickr/runs (asks first).
62
72
 
63
- Usage: npx @sickr/cli <command> [options]
73
+ LIVE LOOK (Replay Pro) — passive streaming to a watching browser.
74
+ live Stream the current session to sickr.ai/r/<your-link> in
75
+ real time. Browser steer messages land in
76
+ ~/.sickr/inbox/<urlid>.md and your terminal prints them.
77
+ Requires \`sickr login\` + Replay Pro entitlement.
78
+ live status Show pid + connection state.
79
+ live stop Stop the sidecar.
64
80
 
65
- Commands:
66
- replay Auto mode: installs Claude + Codex recording hooks. If the
67
- signed-in user has Replay Pro, starts Live Look as well.
68
- replay init all|claude|codex
69
- Install recording hooks under the unified command name.
70
- replay share Publish a redacted replay to sickr.ai/r/<id>.
71
- replay status Show Live Look sidecar status.
72
- workflow connect --agent-id <id>
73
- Connect this machine to a configured SICKR workflow agent.
74
- workflow start --agent-id <id>
75
- Start the workflow orchestrator for that configured agent.
76
- workflow status
77
- Show running workflow daemon status.
78
- workflow rotate | workflow disconnect
79
- Rotate or revoke this machine's workflow agent key.
81
+ REMOTE CONTROL (Replay Pro) — browser keystrokes drive the agent.
82
+ run <agent> Wrap an agent in a PTY sickr owns; browser steer
83
+ messages are written directly into the agent's stdin.
84
+ Real remote control, not pasteboard.
85
+ sickr run claude Claude Code under sickr
86
+ sickr run codex Codex under sickr
87
+ sickr run <bin> arbitrary binary
88
+ Flags:
89
+ --mode auto (default) inject the agent's
90
+ "no prompt / full perms" flag so it
91
+ doesn't stall on tool confirms the
92
+ operator can't see.
93
+ --mode interactive pass agent flags through
94
+ verbatim agent prompts for tool use.
95
+ Requires \`sickr login\` + Replay Pro entitlement.
96
+ Codex 0.133+ needs \`/hooks\` typed once to trust the
97
+ recorder; Claude is silent (hooks auto-installed).
80
98
 
81
- Legacy replay commands remain supported:
82
- init <agent> Install recording hooks for an agent (REQUIRED — no default)
83
- and start capturing to ~/.sickr/runs (secrets redacted):
84
- claude Claude Code (.claude/settings.json)
85
- codex Codex (.codex/hooks.json needs Codex 0.133+)
86
- all both of the above (feeds the combined view)
87
- Flag: --no-name (label prompts "Human", not your login name)
88
- open [run] Render a run to a local HTML timeline and open it. 100% local.
89
- Defaults to the newest run; pass a run id, or --codex/--claude
90
- for the newest run of that agent. Combine across agents with a
91
- window: --today, --since <2h|30m|1d>, or --all (interleaved,
92
- filterable by agent, sortable by prompt/response time).
93
- share [run] Redact and publish ONE run to a public sickr.ai/r/<id> link
94
- (shows a preview and asks first). Links expire after 24h.
95
- --open also open the published link in your browser
96
- --yes skip the confirmation prompt
97
- Or publish a COMBINED multi-agent view with a window:
98
- --today / --since <2h|30m|1d> / --all (+ --claude/--codex).
99
- list List recorded runs, newest first.
100
- stop Stop recording — removes SICKR's hooks from this project.
101
- Your recorded runs are kept; run \`init\` to start again.
102
- clear Delete all local runs in ~/.sickr/runs (asks first).
103
- login Sign in with GitHub (optional — unlocks persistent shares and
104
- Replay Pro cohort eligibility). Zero-account use still works.
105
- logout Forget the local login. Server-side session stays valid until
106
- it expires; revoke from your account page if needed.
107
- whoami Show who you're logged in as.
108
- live Replay Pro: stream the current session to sickr.ai/r/<your-link>
109
- in real time. Requires \`login\` and Replay Pro entitlement.
110
- replay live start the sidecar (foreground; ^C exits)
111
- replay live status show pid + connection state
112
- replay live stop stop the sidecar
113
- While running, steer messages from the watching browser are
114
- saved to ~/.sickr/inbox/<urlid>.md and printed in your terminal.
115
- run <agent> Replay Pro (Phase 2): wrap an agent in a PTY this CLI owns.
116
- Browser steer messages land directly in the agent's stdin —
117
- real remote control, no copy-paste from inbox.
118
- sickr run claude spawn Claude Code under sickr (auto-perms)
119
- sickr run codex same for Codex (auto-perms)
120
- sickr run <bin> arbitrary command
121
- Modes:
122
- --mode auto (default) inject the agent's "no prompt /
123
- full permissions" flag so it
124
- doesn't stall on tool confirms
125
- the operator can't see (claude:
126
- --dangerously-skip-permissions;
127
- codex: --dangerously-bypass-
128
- approvals-and-sandbox)
129
- --mode interactive pass agent flags through verbatim;
130
- agent will prompt for tool use
131
- \`node-pty\` ships as an optional dep + auto-installs with the
132
- CLI on supported platforms (mac, Linux, Windows 10+).
133
- Browsers can override per-message: {mode:'queue'|'steer',
134
- submit:true|false}; default is auto-steer with submit.
135
- agent connect --agent-id <id>
136
- Connect this machine to a configured SICKR agent using GitHub
137
- browser approval. Stores the agent key in ~/.sickr/agent.json.
138
- agent status Show the connected agent, org and team.
139
- agent rotate Rotate this machine's agent key.
140
- agent disconnect
141
- Revoke this machine's agent key and remove it locally.
142
- help Show this help.
99
+ ACCOUNT
100
+ login Sign in with GitHub. Unlocks persistent shares
101
+ (24h 7d) and Replay Pro entitlement.
102
+ logout Forget the local login.
103
+ whoami Show who you're signed in as.
143
104
 
144
- Requires Node 18+. Codex capture needs Codex CLI 0.133+ (run /hooks to trust);
145
- Claude Code: any hooks-capable build.
105
+ WORKFLOW (sickr-managed agent + ticketing)
106
+ workflow connect --agent-id <id> Approve this machine for a configured
107
+ workflow agent (GitHub browser flow).
108
+ workflow start --agent-id <id> Start the orchestrator for an agent.
109
+ workflow status Show running daemon status.
110
+ workflow rotate | disconnect Rotate or revoke this machine's key.
146
111
 
147
- ────────────────────────────────────────────────────────────────────
148
- This replays your AI coding agents on ONE machine. SICKR governs your whole team.
149
- Issue tracking + your team + automation + agents — one governed workflow for
150
- audit, accountability, productivity and confidence.
112
+ help Show this help.
151
113
 
152
- · Gates & approvals work holds at plan sign-off, review, merge and
153
- validation checks until each one passes.
154
- · Humans + agents on one board — agents are first-class teammates with
155
- roles, capacity and accountability, not a side channel.
156
- · A full, signed-off audit trail across every actor and every change.
157
- · Runs 24/7 — produce as much work as you like; the team handles it.
114
+ Requires Node 20+. Codex capture needs Codex CLI 0.133+.
158
115
 
159
- Free tier available · bring your own Claude or Codex subscription.
160
- https://sickr.ai
116
+ ────────────────────────────────────────────────────────────────────
117
+ sickr also governs your whole team — issue tracking + humans + agents on one
118
+ board, gates & approvals, signed audit trail, runs 24/7. Free tier available;
119
+ bring your own Claude or Codex subscription. → https://sickr.ai
161
120
  `;
162
121
  export function currentRunId(cc) {
163
122
  return String(cc.session_id ?? 'session');
@@ -860,6 +819,24 @@ async function fetchReplayProEntitlement() {
860
819
  return false;
861
820
  }
862
821
  }
822
+ /** Gate a Pro-only command. Returns true if the user is allowed; otherwise
823
+ * prints a friendly explanation and returns false. Distinguishes the three
824
+ * failure modes (not-logged-in / logged-in-no-pro / network-fail) so the
825
+ * operator knows exactly what to do next. */
826
+ async function requireReplayPro(commandLabel) {
827
+ const creds = readCredentials();
828
+ if (!creds) {
829
+ process.stderr.write(`sickr: \`${commandLabel}\` is a Replay Pro feature.\n` +
830
+ ` run \`sickr login\` first — your Pro entitlement is attached to your GitHub account.\n`);
831
+ return false;
832
+ }
833
+ if (await fetchReplayProEntitlement())
834
+ return true;
835
+ process.stderr.write(`sickr: \`${commandLabel}\` is a Replay Pro feature.\n` +
836
+ ` you are signed in as ${creds.login}, but your account isn't on Replay Pro.\n` +
837
+ ` join the rolling-cohort waitlist → https://sickr.ai/#waitlist\n`);
838
+ return false;
839
+ }
863
840
  async function handleReplay(rest) {
864
841
  const sub = replaySubcommand(rest);
865
842
  if (!sub) {
@@ -933,6 +910,10 @@ async function handleReplay(rest) {
933
910
  liveStatus();
934
911
  return;
935
912
  }
913
+ if (!(await requireReplayPro('sickr replay live'))) {
914
+ process.exit(3);
915
+ return;
916
+ }
936
917
  await startLive({ verbose: replayRest.includes('--verbose') || replayRest.includes('-v'), background: replayRest.includes('--background') });
937
918
  return;
938
919
  }
@@ -1132,6 +1113,10 @@ async function main() {
1132
1113
  liveStatus();
1133
1114
  return;
1134
1115
  }
1116
+ if (!(await requireReplayPro('sickr live'))) {
1117
+ process.exit(3);
1118
+ return;
1119
+ }
1135
1120
  // default: start (foreground)
1136
1121
  const opts = { verbose: rest.includes('--verbose') || rest.includes('-v'), background: rest.includes('--background') };
1137
1122
  await startLive(opts);
@@ -1180,6 +1165,10 @@ async function main() {
1180
1165
  const passthroughFlags = flags.filter((f) => f !== '--verbose' && f !== '-v');
1181
1166
  const agentArgs = [...passthroughFlags, ...positional.slice(1)];
1182
1167
  const verbose = flags.includes('--verbose') || flags.includes('-v');
1168
+ if (!(await requireReplayPro('sickr run'))) {
1169
+ process.exit(3);
1170
+ return;
1171
+ }
1183
1172
  const { startRun } = await import('./run.js');
1184
1173
  try {
1185
1174
  await startRun({ agent, agentArgs, verbose, mode });
package/dist/run.js CHANGED
@@ -295,6 +295,11 @@ export async function startRun(opts) {
295
295
  else if (mode === 'interactive') {
296
296
  process.stdout.write(` mode=interactive — agent will prompt for tool use; you confirm in the PTY\n`);
297
297
  }
298
+ if (opts.agent === 'codex') {
299
+ // Codex 0.133+ gates new hooks until trusted; without trust the recorder
300
+ // is dormant and /r/<urlid> stays empty even though the PTY is live.
301
+ process.stdout.write(` codex hooks: type \`/hooks\` once inside codex to trust the recorder.\n`);
302
+ }
298
303
  process.stdout.write(` browser steer messages land directly in your agent. ^C exits.\n\n`);
299
304
  const pty = ptySpawn(agentBin, effectiveArgs, {
300
305
  name: 'xterm-256color',
@@ -388,12 +393,28 @@ export async function startRun(opts) {
388
393
  if (m.kind === 'steer' && m.text) {
389
394
  const decision = decideSteer(m);
390
395
  if (decision.target === 'pty' && decision.bytes != null) {
396
+ // Submit-fix (2026-06-01): Claude Code's TUI treats a burst of
397
+ // characters arriving with no inter-keystroke gap as a paste
398
+ // — and within a paste, \r is an inline newline, NOT a submit.
399
+ // Text appeared in the input box but never got sent until the
400
+ // operator manually hit Enter. Split the write: body first,
401
+ // then a short delay, then a standalone \r so it lands as a
402
+ // discrete Enter keypress instead of "tail of a paste".
403
+ const bytes = decision.bytes;
404
+ const bodyOnly = bytes.endsWith('\r') ? bytes.slice(0, -1) : bytes;
405
+ const submit = bytes.endsWith('\r');
391
406
  try {
392
- pty.write(decision.bytes);
407
+ if (bodyOnly.length > 0)
408
+ pty.write(bodyOnly);
409
+ if (submit)
410
+ setTimeout(() => { try {
411
+ pty.write('\r');
412
+ }
413
+ catch { /* pty exited */ } }, 80);
393
414
  }
394
415
  catch { /* PTY may have exited */ }
395
416
  if (opts.verbose)
396
- process.stderr.write(`sickr: pty steer ${decision.bytes.length}b\n`);
417
+ process.stderr.write(`sickr: pty steer ${bytes.length}b${submit ? ' (split for submit)' : ''}\n`);
397
418
  }
398
419
  else {
399
420
  appendInbox(urlid, m.text, m.at ?? new Date().toISOString());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sickr/cli",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "type": "module",
5
5
  "description": "npx @sickr/cli - replay, live look, and workflow orchestration for AI coding agents.",
6
6
  "bin": { "replay": "dist/cli.js", "sickr": "dist/cli.js" },