Skip to content

Commit 8e00a21

Browse files
fix onboarding setup flow
1 parent 5b99876 commit 8e00a21

11 files changed

Lines changed: 55 additions & 57 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@archastro/redline": patch
3+
---
4+
5+
Update the public setup flow for the live Chrome Web Store and default npm
6+
registry, and close the local pairing bridge automatically so Chrome-first
7+
onboarding continues in its original tab.

README.md

Lines changed: 14 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,6 @@ Redline combines a Chrome extension, a local helper, and an open agent skill.
1010
Select text on a page, leave the requested change in context, and ask your
1111
agent to pull it. Built by [ArchAstro](https://archastro.ai).
1212

13-
> The Chrome Web Store submission is under review. npm 0.2.x uses the unpacked
14-
> extension workflow below; npm 0.3 and newer use Chrome Web Store pairing.
15-
1613
```
1714
[ Chrome extension ] --local--> [ Helper @ 127.0.0.1:7878 ] --local--> [ Coding agent ]
1815
select + comment private local state pull + act
@@ -34,44 +31,23 @@ Prerequisites: macOS or Linux, Node.js 18 or newer, Bash, curl, and jq, plus
3431
Chrome or another Chromium-based browser. Windows and Safari are not currently
3532
supported.
3633

37-
### npm 0.2.x
38-
39-
npm 0.2.x installs an unpacked extension:
40-
41-
```bash
42-
npm install -g @archastro/redline --registry=https://registry.npmjs.org
43-
redline setup --with-screenshots
44-
redline start
45-
```
46-
47-
Then open `chrome://extensions`, enable **Developer mode**, choose
48-
**Load unpacked**, and select `~/.redline/extension`.
49-
50-
`--with-screenshots` enables Redline on normal HTTP/HTTPS pages and allows
51-
optional visible-page screenshots. Use `redline setup --local-only` for the
52-
lowest-permission localhost workflow.
53-
54-
npm 0.2.x setup also installs or updates legacy Claude and Codex plugin state.
55-
npm 0.3 removes that side effect and replaces those plugins with the portable
56-
skill below.
57-
58-
### npm 0.3+ and the Chrome Web Store
34+
1. [Install Redline from the Chrome Web Store](https://chromewebstore.google.com/detail/redline/bbllmeihbcmemadgmongicpklkjjgoaf).
35+
2. Install the CLI and portable agent skill:
5936

60-
The Store listing is pending review:
61-
62-
[Install Redline from the Chrome Web Store](https://chromewebstore.google.com/detail/redline/bbllmeihbcmemadgmongicpklkjjgoaf)
37+
```bash
38+
npm install -g @archastro/redline
39+
npx skills add ArchAstro/redline
40+
```
6341

64-
Once the listing is available, install the extension and run:
42+
3. Start the local helper and pair the extension:
6543

66-
```bash
67-
npm install -g @archastro/redline --registry=https://registry.npmjs.org
68-
npx skills add ArchAstro/redline
69-
redline setup
70-
```
44+
```bash
45+
redline setup
46+
```
7147

72-
The standard skills CLI owns skill installation and updates in npm 0.3+.
73-
Redline's 0.3+ CLI never installs, updates, removes, or inspects agent skills
74-
or legacy plugin state.
48+
The standard skills CLI owns skill installation and updates. Redline's CLI
49+
never installs, updates, removes, or inspects agent skills or legacy plugin
50+
state.
7551

7652
`redline setup` starts the local helper and opens a short-lived consent page.
7753
Approve it to pair the extension with the local helper. No ArchAstro account
@@ -137,13 +113,9 @@ browser data.
137113
For a one-off setup without a global install:
138114

139115
```bash
140-
npx --yes --@archastro:registry=https://registry.npmjs.org \
141-
--package @archastro/redline redline setup
116+
npx --yes --package @archastro/redline redline setup
142117
```
143118

144-
The explicit npm registry keeps setup working on machines that map the
145-
`@archastro` scope to a private package registry.
146-
147119
## Local-first data model
148120

149121
Redline listens only on `127.0.0.1` and stores its state under `~/.redline` by

extension/background.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,10 @@ function validConnectSender(msg, sender) {
212212
exactConnectUrl(sender.url) && exactConnectUrl(sender.tab.url);
213213
}
214214

215+
async function returnToOnboarding(connectTabId) {
216+
await chrome.tabs.remove(connectTabId);
217+
}
218+
215219
class RedlineExtensionError extends Error {
216220
constructor(code, message) {
217221
super(message);
@@ -988,6 +992,11 @@ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
988992
});
989993
await chrome.alarms.create(PAIRING_SECRET_ALARM, { when: Date.parse(msg.expires_at) });
990994
});
995+
try {
996+
await returnToOnboarding(sender.tab.id);
997+
} catch {
998+
// Pairing is staged even if the bridge tab closes during handoff.
999+
}
9911000
sendResponse({ ok: true, status: 'staged' });
9921001
return;
9931002
}

extension/onboarding.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ <h1 id="setup-title">Connect the local helper</h1>
2525
Checking for Redline on this computer...
2626
</p>
2727
<div id="setup-command" class="command-row">
28-
<code>npx --yes @archastro/redline setup</code>
28+
<code>npx --yes --package @archastro/redline redline setup</code>
2929
<button type="button" id="copy-command" class="secondary" title="Copy setup command">
3030
Copy
3131
</button>

extension/onboarding.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
'use strict';
33

44
const SECRET_KEY = 'redline_pairing_secret';
5-
const SETUP_COMMAND = 'npx --yes @archastro/redline setup';
5+
const SETUP_COMMAND = 'npx --yes --package @archastro/redline redline setup';
66

77
function createOnboardingController({
88
connectionClient, localStorage, sessionStorage, view, siteEnabler = null,
@@ -256,7 +256,7 @@
256256
disclosure.hidden = true;
257257
siteStep.hidden = true;
258258
declinedStep.hidden = true;
259-
status.textContent = 'Run the setup command, then keep this page open.';
259+
status.textContent = 'Run this once in Terminal. This page will continue automatically.';
260260
},
261261
showStatus(state) {
262262
const messages = {

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

runtime/server.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ async function requestIsAuthorized(req) {
254254
return null;
255255
}
256256

257-
const CONNECT_HTML = '<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Connect Redline</title><body><main><h1>Connect Redline</h1><p>Open the Redline extension to review the local-data disclosure and finish connecting this Chrome profile.</p></main></body></html>';
257+
const CONNECT_HTML = '<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Connect Redline</title><body><main><h1>Connecting to Redline</h1><p>This secure handoff tab closes automatically. Continue in the Redline setup tab.</p></main></body></html>';
258258

259259
const server = http.createServer(async (req, res) => {
260260
if (duplicateSecurityHeader(req)) {

tests/extension-connection.test.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,9 @@ test('packaged fragment reader rejects nonliteral pairing fragment spellings', (
584584
}
585585
});
586586

587-
function fragmentBackground(localInitial = {}, devConfig, { failInjection = false, omitAccessApis = false } = {}) {
587+
function fragmentBackground(localInitial = {}, devConfig, {
588+
failInjection = false, omitAccessApis = false,
589+
} = {}) {
588590
const session = memoryStorage();
589591
const local = memoryStorage(localInitial);
590592
const storageAccess = [];
@@ -628,6 +630,7 @@ function fragmentBackground(localInitial = {}, devConfig, { failInjection = fals
628630
}];
629631
},
630632
async create(details) { installEvents.push(['create', structuredClone(details)]); },
633+
async remove(tabId) { installEvents.push(['remove', tabId]); },
631634
onUpdated: { addListener() {} },
632635
onRemoved: { addListener() {} },
633636
},
@@ -719,6 +722,9 @@ test('background stages a fragment secret only from the exact packaged top-frame
719722
'create', 'redline-pairing-secret-expiry',
720723
{ when: Date.parse(background.session.data.redline_pairing_secret.expires_at) },
721724
]);
725+
assert.deepEqual(background.installEvents, [
726+
['remove', 17],
727+
]);
722728

723729
const rejected = [
724730
[{ ...message, source: 'page-script' }, sender],

tests/onboarding.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -681,9 +681,9 @@ test('extension-first onboarding exposes one exact copyable setup command and a
681681
const source = fs.readFileSync(ONBOARDING_PATH, 'utf8');
682682
const { SETUP_COMMAND, bindOnboardingPage } = require(ONBOARDING_PATH);
683683

684-
assert.equal(SETUP_COMMAND, 'npx --yes @archastro/redline setup');
684+
assert.equal(SETUP_COMMAND, 'npx --yes --package @archastro/redline redline setup');
685685
assert.equal(html.split(SETUP_COMMAND).length - 1, 1);
686-
assert.match(html, /<code>npx --yes @archastro\/redline setup<\/code>/);
686+
assert.match(html, /<code>npx --yes --package @archastro\/redline redline setup<\/code>/);
687687
assert.match(html, /id="copy-command"[^>]+title="Copy setup command"/);
688688
assert.equal(typeof bindOnboardingPage, 'function');
689689
assert.match(source, /navigator\.clipboard\.writeText\(SETUP_COMMAND\)/);

tests/public-release.test.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ test('README documents the portable skill and terminal invocation', () => {
136136
assert.match(read('skills/redline/SKILL.md'), /^name:\s*redline$/m);
137137
});
138138

139-
test('public launch guidance distinguishes the current release from Store pairing', () => {
139+
test('public launch guidance uses the live Store pairing flow', () => {
140140
const readme = read('README.md');
141141
const security = read('SECURITY.md');
142142
const contributing = read('CONTRIBUTING.md');
@@ -145,12 +145,14 @@ test('public launch guidance distinguishes the current release from Store pairin
145145
encoding: 'utf8',
146146
});
147147

148-
assert.match(readme, /Chrome Web Store[^.]*under review/i);
149-
assert.match(readme, /npm 0\.2\.x[^.]*unpacked extension/i);
150-
assert.match(readme, /npm 0\.3[^.]*Chrome Web Store/i);
151-
assert.match(readme, /0\.2\.x[^.]*Claude and Codex plugin state/i);
152148
assert.match(readme, /https:\/\/chromewebstore\.google\.com\/detail\/redline\/bbllmeihbcmemadgmongicpklkjjgoaf/);
149+
assert.match(readme, /npm install -g @archastro\/redline/);
150+
assert.match(readme, /npx skills add ArchAstro\/redline/);
151+
assert.match(readme, /redline setup/);
153152
assert.match(readme, /pair[^.]*local helper/i);
153+
assert.doesNotMatch(readme, /under review|pending review/i);
154+
assert.doesNotMatch(readme, /npm 0\.2\.x/i);
155+
assert.doesNotMatch(readme, /--registry|@archastro:registry/i);
154156
assert.doesNotMatch(readme, /command-line tools without an `Origin` header can access the sidecar locally/i);
155157
assert.match(security, /CLI credential/i);
156158
assert.match(security, /paired-browser credential/i);

0 commit comments

Comments
 (0)