@sickr/replay 0.4.5 → 0.4.6
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/cli.js +33 -28
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { pathToFileURL } from 'node:url';
|
|
3
3
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, statSync, unlinkSync } from 'node:fs';
|
|
4
|
-
import { homedir } from 'node:os';
|
|
4
|
+
import { homedir, userInfo } from 'node:os';
|
|
5
5
|
import { join, dirname } from 'node:path';
|
|
6
|
-
import { spawn } from 'node:child_process';
|
|
6
|
+
import { spawn, execFileSync } from 'node:child_process';
|
|
7
7
|
import { appendEvent, loadRun, runsDir, latestRunId } from './recorder.js';
|
|
8
8
|
import { mergeHooks, removeHooks } from './hookConfig.js';
|
|
9
9
|
import { renderRunHtml } from './render.js';
|
|
@@ -30,8 +30,8 @@ Commands:
|
|
|
30
30
|
runs to ~/.sickr/runs (secrets redacted).
|
|
31
31
|
--codex install for Codex (.codex/hooks.json) instead of
|
|
32
32
|
Claude Code (.claude/settings.json)
|
|
33
|
-
--
|
|
34
|
-
(default
|
|
33
|
+
--no-name label your prompts "Human" instead of your
|
|
34
|
+
login/git name (default is your login name)
|
|
35
35
|
open [run] Render a run to a local HTML timeline and open it in your
|
|
36
36
|
browser. 100% local — nothing is uploaded. Defaults to the
|
|
37
37
|
newest run; pass a run id, or --codex / --claude to open the
|
|
@@ -71,14 +71,28 @@ const PROVIDERS = {
|
|
|
71
71
|
function configPath() {
|
|
72
72
|
return join(homedir(), '.sickr', 'config.json');
|
|
73
73
|
}
|
|
74
|
-
/**
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
74
|
+
/** The machine's own identity — git user.name, else OS username, else "Human". */
|
|
75
|
+
function loginName() {
|
|
76
|
+
try {
|
|
77
|
+
const n = execFileSync('git', ['config', 'user.name'], { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
|
|
78
|
+
if (n)
|
|
79
|
+
return n;
|
|
80
|
+
}
|
|
81
|
+
catch { /* git not configured */ }
|
|
82
|
+
try {
|
|
83
|
+
const u = userInfo().username;
|
|
84
|
+
if (u)
|
|
85
|
+
return u;
|
|
86
|
+
}
|
|
87
|
+
catch { /* no os user */ }
|
|
88
|
+
return 'Human';
|
|
89
|
+
}
|
|
90
|
+
/** Human label for prompts: the name stored at init (login name, or "Human" if anonymized). */
|
|
91
|
+
function resolveName() {
|
|
78
92
|
try {
|
|
79
93
|
const c = JSON.parse(readFileSync(configPath(), 'utf8'));
|
|
80
|
-
if (c.
|
|
81
|
-
return c.
|
|
94
|
+
if (c.name)
|
|
95
|
+
return c.name;
|
|
82
96
|
}
|
|
83
97
|
catch { /* no config */ }
|
|
84
98
|
return 'Human';
|
|
@@ -87,13 +101,13 @@ function resolveHandle() {
|
|
|
87
101
|
export function handleRecord(input, provider = 'claude') {
|
|
88
102
|
try {
|
|
89
103
|
const cc = JSON.parse(input);
|
|
90
|
-
appendEvent(currentRunId(cc), cc, { human:
|
|
104
|
+
appendEvent(currentRunId(cc), cc, { human: resolveName(), agent: PROVIDERS[provider].label });
|
|
91
105
|
}
|
|
92
106
|
catch {
|
|
93
107
|
/* swallow: recording is best-effort and must not disrupt the session */
|
|
94
108
|
}
|
|
95
109
|
}
|
|
96
|
-
export function handleInit(provider,
|
|
110
|
+
export function handleInit(provider, noName = false) {
|
|
97
111
|
const p = PROVIDERS[provider];
|
|
98
112
|
const settingsPath = p.settingsPath();
|
|
99
113
|
const settings = existsSync(settingsPath) ? JSON.parse(readFileSync(settingsPath, 'utf8')) : {};
|
|
@@ -105,17 +119,11 @@ export function handleInit(provider, handle) {
|
|
|
105
119
|
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
106
120
|
writeFileSync(settingsPath, JSON.stringify(merged, null, 2) + '\n');
|
|
107
121
|
mkdirSync(runsDir(), { recursive: true });
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
catch { /* none */ }
|
|
114
|
-
writeFileSync(configPath(), JSON.stringify({ ...existing, handle }, null, 2) + '\n');
|
|
115
|
-
}
|
|
116
|
-
const labelLine = handle
|
|
117
|
-
? `Your prompts will be labelled "${handle}".\n`
|
|
118
|
-
: 'Tip: set SICKR_HANDLE or run `init --as "<name>"` to label your prompts.\n';
|
|
122
|
+
// Always (re)write the name so re-running init resets it — no arbitrary names
|
|
123
|
+
// (avoids impersonation on public shares); just the login name, or "Human".
|
|
124
|
+
const name = noName ? 'Human' : loginName();
|
|
125
|
+
writeFileSync(configPath(), JSON.stringify({ name }, null, 2) + '\n');
|
|
126
|
+
const labelLine = `Your prompts will be labelled "${name}"${noName ? '' : ' — run `init --no-name` to anonymize'}.\n`;
|
|
119
127
|
const nextSteps = provider === 'codex'
|
|
120
128
|
? 'Next: in Codex, run `/hooks` to review & trust these hooks (Codex gates new hooks),\nthen use Codex as normal and: npx @sickr/replay open --codex\n'
|
|
121
129
|
: 'Use Claude Code as normal, then: npx @sickr/replay open\n';
|
|
@@ -332,12 +340,9 @@ async function main() {
|
|
|
332
340
|
case 'record':
|
|
333
341
|
handleRecord(await readStdin(), provider);
|
|
334
342
|
return;
|
|
335
|
-
case 'init':
|
|
336
|
-
|
|
337
|
-
const handle = asIdx >= 0 ? rest[asIdx + 1] : undefined;
|
|
338
|
-
handleInit(provider, handle);
|
|
343
|
+
case 'init':
|
|
344
|
+
handleInit(provider, rest.includes('--no-name'));
|
|
339
345
|
return;
|
|
340
|
-
}
|
|
341
346
|
case 'open': {
|
|
342
347
|
const openProvider = rest.includes('--codex') ? 'codex' : rest.includes('--claude') ? 'claude' : undefined;
|
|
343
348
|
handleOpen(rest.find((a) => !a.startsWith('-')), openProvider);
|
package/package.json
CHANGED