context-carwash 0.1.2 → 0.1.3

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
@@ -18,7 +18,7 @@ npx context-carwash preview # sample meters in your terminal, nothing instal
18
18
  npx context-carwash install # lists what it will change, then asks
19
19
  ```
20
20
 
21
- To update later, run `npx context-carwash@latest install` again. Waiting briefs are kept. The `@latest` matters: without it npx may rerun the copy it downloaded last time. If it does, the installer says a newer version is out before asking to go ahead.
21
+ To update later, run `npx context-carwash install` again. Waiting briefs are kept. If npx reruns an older copy it downloaded before, the installer notices that npm has a newer version and installs that one instead.
22
22
 
23
23
  The installer copies itself to `~/.carwash/app` and makes three changes to Claude Code, all listed before you confirm:
24
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-carwash",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "A quiet context meter and deliberate fresh-session handoff for Claude Code.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/cli.mjs CHANGED
@@ -2,7 +2,7 @@ import { appendFileSync, existsSync, statSync, writeFileSync } from 'node:fs';
2
2
  import { createInterface } from 'node:readline';
3
3
  import { applyInstall, applyUninstall, describeInstall, describeUninstall, packageVersion, planInstall, planUninstall } from './install/install.mjs';
4
4
  import { UserError } from './install/settings.mjs';
5
- import { latestVersion, updateNotice } from './install/update.mjs';
5
+ import { isNewer, latestVersion, runRelease } from './install/update.mjs';
6
6
  import { errorLogPath, welcomedPath } from './paths.mjs';
7
7
  import { render } from './statusline/render.mjs';
8
8
  import { statusline } from './statusline/run.mjs';
@@ -88,7 +88,7 @@ function logError(env, error) {
88
88
  }
89
89
  }
90
90
 
91
- export async function main(argv, { env = process.env, stdin = process.stdin, stdout = process.stdout, stderr = process.stderr, latest = latestVersion } = {}) {
91
+ export async function main(argv, { env = process.env, stdin = process.stdin, stdout = process.stdout, stderr = process.stderr, latest = latestVersion, handOff = runRelease } = {}) {
92
92
  const [command, ...rest] = argv;
93
93
  const yes = rest.includes('--yes') || rest.includes('-y');
94
94
  try {
@@ -107,11 +107,21 @@ export async function main(argv, { env = process.env, stdin = process.stdin, std
107
107
  return 0;
108
108
  }
109
109
  case 'install': {
110
+ // npx may be rerunning an old download. If npm has something newer,
111
+ // that release does the install. Once only: the newer copy is not
112
+ // asked to check again.
113
+ if (!env.CARWASH_HANDED_OFF) {
114
+ const current = packageVersion();
115
+ const newest = await latest({ env });
116
+ if (isNewer(newest, current)) {
117
+ stdout.write(`This is Context Carwash ${current}, and ${newest} is out. Installing ${newest} instead.\n\n`);
118
+ const status = handOff(newest, argv, { env });
119
+ if (status !== null) return status;
120
+ stdout.write(`Could not start ${newest}, so continuing with ${current}. For the newer one: npx context-carwash@latest install\n\n`);
121
+ }
122
+ }
110
123
  const plan = planInstall({ env });
111
124
  stdout.write(describeInstall(plan) + '\n\n');
112
- // Last, so it sits right above the question it changes the answer to.
113
- const notice = updateNotice(packageVersion(), await latest({ env }));
114
- if (notice) stdout.write(notice + '\n\n');
115
125
  if (!(await confirm('Proceed?', { yes, stdin, stdout }))) {
116
126
  stdout.write('Nothing was changed.\n');
117
127
  return 1;
@@ -1,5 +1,8 @@
1
- // Whether a newer Context Carwash is on npm. Only the installer asks, since
2
- // npx can quietly rerun a copy it downloaded earlier. The meter and /wash never
1
+ import { spawnSync } from 'node:child_process';
2
+
3
+ // Whether a newer Context Carwash is on npm, and handing over to it. Only the
4
+ // installer asks, since npx can quietly rerun a copy it downloaded earlier, and
5
+ // people should not have to know to type @latest. The meter and /wash never
3
6
  // use the network.
4
7
 
5
8
  const LATEST_URL = 'https://registry.npmjs.org/context-carwash/latest';
@@ -34,11 +37,17 @@ export async function latestVersion({ env = process.env, timeoutMs = TIMEOUT_MS
34
37
  }
35
38
  }
36
39
 
37
- // What the installer says before asking, or null when this is the latest.
38
- export function updateNotice(current, latest) {
39
- if (!isNewer(latest, current)) return null;
40
- return [
41
- `A newer Context Carwash is out: ${latest}. This installer is ${current}.`,
42
- 'To install the newer one, answer no and run: npx context-carwash@latest install',
43
- ].join('\n');
40
+ // Run `carwash <args>` from the given release instead of this one, in this
41
+ // terminal, so its questions reach the person. Pinned to the exact version, so
42
+ // the newer copy finds itself up to date and does not hand off again. Resolves
43
+ // to its exit code, or null if npx could not be started.
44
+ export function runRelease(version, args, { env = process.env, platform = process.platform } = {}) {
45
+ const npx = platform === 'win32' ? 'npx.cmd' : 'npx';
46
+ // npx.cmd is a batch file, which Windows only runs through a shell.
47
+ const result = spawnSync(npx, ['--yes', `context-carwash@${version}`, ...args], {
48
+ stdio: 'inherit',
49
+ env: { ...env, CARWASH_HANDED_OFF: version },
50
+ shell: platform === 'win32',
51
+ });
52
+ return result.error || result.status === null ? null : result.status;
44
53
  }