@getopencrawl/cli 0.4.8 → 0.4.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/README.md CHANGED
@@ -47,17 +47,18 @@ or forbidden, 64 invalid arguments, 130 interrupted.
47
47
  ## Updates and distribution
48
48
 
49
49
  TypeScript compiled with Bun 1.3.14 produces a self-contained binary. Users need
50
- Node 22+ and npm for the bootstrap, never Bun. npm platform packages cover macOS
50
+ Node 22.15+ and npm for the bootstrap, never Bun. npm platform packages cover macOS
51
51
  arm64/x64, Linux glibc arm64/x64 and Windows x64. Alpine/musl and Windows arm64
52
52
  are not supported in v0. Platform packages are optional dependencies at the exact
53
53
  launcher version; there are no install scripts.
54
54
 
55
- After a command, the launcher starts a detached updater at most once per day.
55
+ Before ordinary commands, the launcher checks for updates at most once per day.
56
+ It awaits the update in the invoking process; hooks never check for updates.
56
57
  It checks the npm `next` release channel, installs into a private user-owned cache with
57
58
  npm integrity verification and install scripts disabled, then atomically selects
58
- the complete release. The next invocation uses it. No sudo or global-directory
59
+ the complete release. The command uses the selected binary. No sudo or global-directory
59
60
  writes are needed. Offline/update failures preserve the working copy and retry
60
- after 15 minutes. Concurrent updater processes share a lock; updates never
61
+ after 15 minutes. Concurrent invocations share an update lock; updates never
61
62
  downgrade. An unused installation updates when it is next invoked, not on a timer.
62
63
 
63
64
  `OPENCRAWL_NO_UPDATE=1` disables automatic updates for reproducible agent runs.
@@ -101,12 +102,35 @@ background upgrades; Glen's small npm entry point for agents.
101
102
 
102
103
  ### Session capture
103
104
 
104
- After signing in, run `opencrawl collect install` to install Claude Code and Codex hooks and the background transcript collector. Review the commands in Codex `/hooks` or desktop Settings > Hooks. The same local configuration covers desktop and terminal sessions.
105
+ After signing in, run `opencrawl collect install` to install Claude Code and Codex hooks and the on-demand transcript uploader. Review the commands in Codex `/hooks` or desktop Settings > Hooks. The same local configuration covers desktop and terminal sessions.
105
106
 
106
- `opencrawl collect status --json` reports the last authenticated identity, queued uploads, last receipt and errors. `collect sync` reconciles active transcripts; `collect flush` retries queued uploads; `collect uninstall` removes OpenCrawl hooks and stops collection while preserving queued data.
107
+ `opencrawl collect status --json` reports the last authenticated identity, queued uploads, last receipt and errors. `collect sync` reconciles active transcripts; `collect flush` processes pending hooks and known transcript tails, then waits for queued uploads; `collect uninstall` removes OpenCrawl hooks and stops collection while preserving queued data.
107
108
 
108
109
  Messages, tool arguments/results and attachments are collected with native session IDs and a stable installation ID. System/developer prompts are excluded. The hosted service determines the current team from login and validates human attribution. Existing collectors and queued personal-scope uploads automatically use that team after updating, without reinstalling or resetting. Self-hosted users can supply `OPENCRAWL_SESSIONS_TOKEN` and `--api` for the portable receiver. See [capture architecture and limits](../docs/session-capture.md).
109
110
 
111
+ The harness runs each hook asynchronously and owns its process. The hook saves
112
+ its notice locally, then competes for one nonblocking uploader lock. The winner
113
+ parses permitted transcripts, spools immutable batches and uploads; other hooks
114
+ exit after saving their notices. On Unix the shell and Node dispatcher replace
115
+ themselves with the native CLI using exec, keeping the harness-owned PID. Capture
116
+ never detaches a child, starts a service or launches a replacement worker.
117
+ Foreground flush/backfill waits for upload ownership and confirmed receipts.
118
+
119
+ No systemd, launchd, cron, or installed daemon is required. Reinstall removes
120
+ legacy OpenCrawl timers. Existing installations upgrade their owned hook settings
121
+ on the next CLI invocation; restart existing sessions to load async settings.
122
+ Legacy synchronous hooks remain local-only until those settings reload.
123
+ The uploader polls known transcripts for 30 seconds after activity, including
124
+ late writes after Stop, and retries failures with backoff while the harness lets
125
+ it run. Later hooks or explicit sync/flush recover retained work after process
126
+ loss. Harness teardown may cancel an async hook; no delivery is possible after
127
+ a sandbox destroys unsent files. An idle interval is not a final-session receipt.
128
+ `collect status` reports pending hooks separately from queued batches.
129
+
130
+ Cloud image setup uses `collect install --harness claude-code --defer-auth
131
+ --backfill skip` without a runtime credential or identity lookup. The first async
132
+ hook binds identity before parsing or uploading, without blocking the agent.
133
+
110
134
  ### Optional history import
111
135
 
112
136
  `collect install` asks terminal users whether to import past Claude Code sessions,
@@ -185,7 +209,7 @@ a separate setup session are supported. Environment variables are visible to
185
209
  commands in that environment; don't paste the credential into the chat or repo.
186
210
 
187
211
  The installer detects `CLAUDE_CODE_REMOTE=true`, installs Claude hooks only and
188
- skips systemd. `--harness claude-code --no-background` also selects this explicitly.
212
+ uses the same service-free uploader as local installations. `--harness claude-code` selects just Claude hooks; `--no-background` remains an accepted compatibility flag.
189
213
  The setup installs the CLI at
190
214
  `$HOME/.local/share/opencrawl-cloud/node_modules/.bin/opencrawl`. After a user
191
215
  message, tool call and image, `collect status` must report a stored receipt and
package/bin/opencrawl.cjs CHANGED
@@ -6,7 +6,7 @@ const fs = require('node:fs');
6
6
  const path = require('node:path');
7
7
  const os = require('node:os');
8
8
  const {createRequire} = require('node:module');
9
- const {spawn, spawnSync} = require('node:child_process');
9
+ const {spawnSync} = require('node:child_process');
10
10
  const {randomUUID} = require('node:crypto');
11
11
  const {parseArgs} = require('node:util');
12
12
  const ROOT = path.resolve(__dirname, '..');
@@ -123,14 +123,10 @@ async function installRelease(version, {registry = REGISTRY} = {}) {
123
123
  fs.renameSync(stage, destination);
124
124
  } finally { fs.rmSync(stage, {recursive: true, force: true}); }
125
125
  }
126
- function scheduleUpdate() {
126
+ async function automaticUpdate() {
127
127
  if (process.env.OPENCRAWL_NO_UPDATE === '1') return;
128
- try {
129
- if (read(path.join(cacheRoot(), 'update.json'))?.checkedAt > Date.now() - DAY) return;
130
- const child = spawn(process.execPath, [__filename, '--internal-update'], {detached: true, stdio: 'ignore', windowsHide: true});
131
- child.on('error', () => {});
132
- child.unref();
133
- } catch {} // updating can never make an ordinary command fail
128
+ try { await update(); }
129
+ catch { try { write(path.join(cacheRoot(), 'update.json'), {checkedAt: Date.now() - DAY + 15 * 60_000}); } catch {} }
134
130
  }
135
131
  async function main(args = process.argv.slice(2)) {
136
132
  if (args[0] === '--internal-update') {
@@ -140,9 +136,9 @@ async function main(args = process.argv.slice(2)) {
140
136
  const selected = activeRoot();
141
137
  // Delegate the launcher too, so later releases can fix bootstrap behavior.
142
138
  if (selected !== ROOT) {
143
- const delegated = spawnSync(process.execPath, [path.join(selected, 'bin/opencrawl.cjs'), ...args], {stdio: 'inherit', windowsHide: true, env: {...process.env, OPENCRAWL_LAUNCHER: process.env.OPENCRAWL_LAUNCHER || __filename, OPENCRAWL_NODE: process.execPath}});
144
- if (delegated.error) throw new Error('Could not start the cached launcher.');
145
- return delegated.signal === 'SIGINT' ? 130 : delegated.status ?? 1;
139
+ process.env.OPENCRAWL_LAUNCHER ||= __filename;
140
+ process.env.OPENCRAWL_NODE = process.execPath;
141
+ return require(path.join(selected, 'bin/opencrawl.cjs')).main(args);
146
142
  }
147
143
  let parsed;
148
144
  try { parsed = parseArgs({args, allowPositionals: true, options: {json: {type: 'boolean'}, 'no-browser': {type: 'boolean'}, api: {type: 'string'}, version: {type: 'boolean', short: 'v'}, help: {type: 'boolean', short: 'h'}}}); }
@@ -152,9 +148,9 @@ async function main(args = process.argv.slice(2)) {
152
148
  process.stdout.write(args.includes('--json') ? JSON.stringify({schemaVersion: 1, data}) + '\n' : data.busy ? 'An update is already running.\n' : data.updated ? `Installed opencrawl ${data.version}. Your next invocation will use it.\n` : `opencrawl ${data.version} is current.\n`);
153
149
  return 0;
154
150
  }
151
+ if (!(args[0] === 'collect' && ['hook','worker'].includes(args[1]))) await automaticUpdate();
155
152
  const root = activeRoot();
156
153
  const result = spawnSync(binary(root), args, {stdio: 'inherit', windowsHide: true, env: {...process.env, OPENCRAWL_LAUNCHER: process.env.OPENCRAWL_LAUNCHER || __filename, OPENCRAWL_NODE: process.execPath}});
157
- scheduleUpdate();
158
154
  if (result.error) throw new Error('Could not start the OpenCrawl binary. Reinstall @getopencrawl/cli.');
159
155
  if (result.signal === 'SIGINT') return 130;
160
156
  return result.status ?? 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getopencrawl/cli",
3
- "version": "0.4.8",
3
+ "version": "0.4.10",
4
4
  "description": "OpenCrawl CLI: sign in now, query the index as features become available",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -17,17 +17,17 @@
17
17
  "directory": "cli"
18
18
  },
19
19
  "engines": {
20
- "node": ">=22"
20
+ "node": ">=22.15"
21
21
  },
22
22
  "publishConfig": {
23
23
  "access": "public",
24
24
  "registry": "https://registry.npmjs.org"
25
25
  },
26
26
  "optionalDependencies": {
27
- "@getopencrawl/cli-darwin-arm64": "0.4.8",
28
- "@getopencrawl/cli-darwin-x64": "0.4.8",
29
- "@getopencrawl/cli-linux-arm64": "0.4.8",
30
- "@getopencrawl/cli-linux-x64": "0.4.8",
31
- "@getopencrawl/cli-win32-x64": "0.4.8"
27
+ "@getopencrawl/cli-darwin-arm64": "0.4.10",
28
+ "@getopencrawl/cli-darwin-x64": "0.4.10",
29
+ "@getopencrawl/cli-linux-arm64": "0.4.10",
30
+ "@getopencrawl/cli-linux-x64": "0.4.10",
31
+ "@getopencrawl/cli-win32-x64": "0.4.10"
32
32
  }
33
33
  }