@north-light/cli 0.3.420 → 0.3.421
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
|
@@ -128,11 +128,12 @@ else console.error(run.reason, run.detail);
|
|
|
128
128
|
## Run it in a container
|
|
129
129
|
|
|
130
130
|
```bash
|
|
131
|
-
docker run -
|
|
131
|
+
docker run --cap-add SYS_ADMIN --cap-add NET_ADMIN --security-opt seccomp=unconfined --security-opt apparmor=unconfined \
|
|
132
|
+
-e CRTRD_TOKEN=<a-secret-you-choose> -p 7777:7777 ghcr.io/northlight-systems/crtrd
|
|
132
133
|
curl -H "Authorization: Bearer <a-secret-you-choose>" http://localhost:7777/healthz
|
|
133
134
|
```
|
|
134
135
|
|
|
135
|
-
The image runs `crtrd` headless behind TCP; every request needs the bearer token. It contains no model credential, so give the agent one before you create a run. Mount a named volume at `/home/agent/.crouter` to keep the canvas across restarts. From Node, [`@north-light/env-docker`](https://github.com/Northlight-Systems/crouter/tree/main/packages/crouter-env-docker) starts and stops this container for you. Details are in [`docker/README.md`](https://github.com/Northlight-Systems/crouter/blob/main/docker/README.md).
|
|
136
|
+
The image runs `crtrd` headless behind TCP; every request needs the bearer token. Its sandbox launcher needs the two capabilities and unconfined seccomp/AppArmor profiles shown. It contains no model credential, so give the agent one before you create a run. Mount a named volume at `/home/agent/.crouter` to keep the canvas across restarts. From Node, [`@north-light/env-docker`](https://github.com/Northlight-Systems/crouter/tree/main/packages/crouter-env-docker) starts and stops this container for you. Details are in [`docker/README.md`](https://github.com/Northlight-Systems/crouter/blob/main/docker/README.md).
|
|
136
137
|
|
|
137
138
|
## Extend crouter
|
|
138
139
|
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { type StartedFlow } from '../../core/model-auth/flows.js';
|
|
2
3
|
import type { AppPrincipalResolver } from './principal.js';
|
|
3
4
|
export declare const VENDOR_SIGNIN_PATH = "/signin/vendor";
|
|
4
5
|
export declare function isVendorSignInPath(pathname: string): boolean;
|
|
6
|
+
export declare function anthropicPage(flow: StartedFlow, nonce: string, returnTo: string, handoff: string): string;
|
|
7
|
+
export declare function openaiPage(flow: StartedFlow, nonce: string, returnTo: string, handoff: string, now?: number): string;
|
|
5
8
|
/** Serve one `/signin/vendor*` request; errors propagate as RunErrors so the
|
|
6
9
|
* listener answers them with contract 2's envelope (RT-LLM-53). */
|
|
7
10
|
export declare function handleVendorSignIn(req: IncomingMessage, res: ServerResponse, url: URL, principal: AppPrincipalResolver): Promise<void>;
|
|
@@ -1,77 +1,192 @@
|
|
|
1
|
-
var
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
var O=Object.defineProperty;var a=(e,t)=>O(e,"name",{value:t,configurable:!0});import{randomBytes as j}from"node:crypto";import{joinedOwner as E}from"../../core/directory/join.js";import{consumeHandoffJti as z,handoffJtiConsumed as y}from"../../core/model-auth/handoff-jti.js";import{completeModelAuthFlow as I,modelAuthProvider as N,readModelAuthFlow as k,startModelAuthFlow as P,waitModelAuthFlow as L}from"../../core/model-auth/flows.js";import{RunError as d}from"../../core/runs/operations.js";import{LONG_POLL_MAX_WAIT_SECONDS as R}from"../../api/long-poll.js";const l="/signin/vendor",$=900,B=R*1e3,G="https://chatgpt.com/#settings/Security";function ce(e){return e===l||e.startsWith(`${l}/`)}a(ce,"isVendorSignInPath");function u(){return new d(401,"unauthorized","invalid vendor sign-in handoff")}a(u,"unauthorized");async function C(e,t){const n=await e.verifyHandoff(t);let r;try{r=E()}catch{r=null}if(n.sub!==r)throw u();return n}a(C,"verifyOwnerHandoff");function U(e){const t=e.headers.authorization;return t?.startsWith("Bearer ")&&t.length>7?t.slice(7):void 0}a(U,"bearer");function x(e,t){const n=e.getAll(t);return n.length===1?n[0]:void 0}a(x,"single");function H(e,t){const n=new URL(e);return n.searchParams.set("status",t),n.toString()}a(H,"returnUrl");function p(e){return e.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t])}a(p,"escapeHtml");function h(e,t,n){e.writeHead(t,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(n))}a(h,"sendJson");async function J(e){const t=[];let n=0;for await(const o of e){if(n+=o.length,n>64*1024)throw new d(400,"invalid_request","request body too large");t.push(o)}let r;try{r=JSON.parse(Buffer.concat(t).toString("utf8"))}catch{throw new d(400,"invalid_request","invalid JSON body")}if(typeof r!="object"||r===null||Array.isArray(r))throw new d(400,"invalid_request","request body must be a JSON object");return r}a(J,"jsonBody");const D=`
|
|
2
|
+
:root{color-scheme:light dark;
|
|
3
|
+
--canvas:#f0f2f4;--surface:#fff;--sunken:#e5e7ea;--zone:#e5e7ea;--neutral:#e5e7ea;--neutral-hover:#d7d9dc;--neutral-pressed:#cbcdd0;
|
|
4
|
+
--accent:#1f4fbf;--accent-hover:#1b45a8;--accent-pressed:#173b8f;--accent-border:#1f4fbf;--accent-subtle:#dce6fb;--accent-fg:#1f4fbf;--on-accent:#fff;
|
|
5
|
+
--warning-bg:#fcedd4;--warning-fg:#8f5200;--danger-bg:#fce5e2;--danger-fg:#bf2a1f;--danger-line:#bf2a1f;
|
|
6
|
+
--text:#15171a;--muted:#505256;--disabled:#919498;--line:#d7d9dc;--line-strong:#787b7f;--focus:#1f4fbf;
|
|
7
|
+
--sans:system-ui,-apple-system,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;
|
|
8
|
+
--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
|
|
9
|
+
@media (prefers-color-scheme:dark){:root{
|
|
10
|
+
--canvas:#0e1012;--surface:#181a1d;--sunken:#212326;--zone:#212326;--neutral:#212326;--neutral-hover:#2f3134;--neutral-pressed:#3c3e41;
|
|
11
|
+
--accent:#2a5cd0;--accent-hover:#2452c4;--accent-pressed:#1f4fbf;--accent-border:#5585ec;--accent-subtle:#15233f;--accent-fg:#7aa7ff;--on-accent:#fff;
|
|
12
|
+
--warning-bg:#35260f;--warning-fg:#f4b45a;--danger-bg:#3b1715;--danger-fg:#ff8175;--danger-line:#d0342a;
|
|
13
|
+
--text:#f0f2f4;--muted:#acaeb2;--disabled:#505256;--line:#2f3134;--line-strong:#787b7f;--focus:#7aa7ff}}
|
|
14
|
+
*,*::before,*::after{box-sizing:border-box}
|
|
15
|
+
[hidden]{display:none!important}
|
|
16
|
+
body{margin:0;min-height:100vh;min-height:100dvh;display:flex;flex-direction:column;background:var(--canvas);color:var(--text);font:400 .9375rem/1.5333 var(--sans);-webkit-text-size-adjust:100%}
|
|
17
|
+
p,h1,ol{margin:0}
|
|
18
|
+
a{color:inherit}
|
|
19
|
+
:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
|
|
20
|
+
.top{display:flex;align-items:center;gap:.5rem;height:3.5rem;flex:none;padding:0 1rem;background:var(--surface);border-bottom:1px solid var(--line)}
|
|
21
|
+
.top svg{width:20px;height:20px;color:var(--accent-fg)}
|
|
22
|
+
.top span{font-weight:600}
|
|
23
|
+
main{flex:1;display:flex;flex-direction:column;align-items:center;padding:2.5rem 1rem}
|
|
24
|
+
.col{width:100%;max-width:36rem}
|
|
25
|
+
.card{display:flex;flex-direction:column;gap:1.5rem;padding:1.5rem;background:var(--surface);border:1px solid var(--line);border-radius:12px}
|
|
26
|
+
.head{display:flex;align-items:center;gap:1rem}
|
|
27
|
+
.logo{position:relative;flex:none;width:3.5rem;height:3.5rem;border-radius:12px;overflow:hidden}
|
|
28
|
+
.logo svg{display:block;width:100%;height:100%}
|
|
29
|
+
.logo::after{content:"";position:absolute;inset:0;border:1px solid var(--line);border-radius:inherit}
|
|
30
|
+
.eyebrow{display:block;font-size:.8125rem;line-height:1.2308;font-weight:500;color:var(--muted)}
|
|
31
|
+
h1{margin-top:.25rem;font-size:1.25rem;line-height:1.3;font-weight:600;letter-spacing:-.02em}
|
|
32
|
+
.steps{list-style:none;padding:0;display:flex;flex-direction:column;gap:1.25rem}
|
|
33
|
+
.steps>li{display:flex;gap:.875rem}
|
|
34
|
+
.n{position:relative;flex:none;display:flex;align-items:center;justify-content:center;width:1.75rem;height:1.75rem;border-radius:9999px;background:var(--neutral);font-size:.8125rem;font-weight:500;font-variant-numeric:tabular-nums}
|
|
35
|
+
.n svg{display:none;width:1rem;height:1rem}
|
|
36
|
+
li.done .n{background:var(--accent-subtle);color:var(--accent-fg)}
|
|
37
|
+
li.done .n span{display:none}
|
|
38
|
+
li.done .n svg{display:block}
|
|
39
|
+
.body{flex:1;min-width:0;display:flex;flex-direction:column;gap:.625rem;padding-top:.125rem}
|
|
40
|
+
.title{font-weight:500}
|
|
41
|
+
.small{font-size:.84375rem;line-height:1.4815;color:var(--muted)}
|
|
42
|
+
.ic{flex:none;width:1rem;height:1rem;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
|
|
43
|
+
.btn{display:inline-flex;align-items:center;justify-content:center;gap:.5rem;min-height:2.5rem;padding:.4rem 1.125rem;border:1px solid transparent;border-radius:8px;background:var(--neutral);color:var(--text);font:500 .9375rem/1.3 var(--sans);text-align:center;text-decoration:none;cursor:pointer;overflow-wrap:break-word;transition:background-color .12s cubic-bezier(.2,0,0,1)}
|
|
44
|
+
.btn:hover{background:var(--neutral-hover)}
|
|
45
|
+
.btn:active{background:var(--neutral-pressed)}
|
|
46
|
+
.btn.primary{background:var(--accent);border-color:var(--accent-border);color:var(--on-accent)}
|
|
47
|
+
.btn.primary:hover{background:var(--accent-hover)}
|
|
48
|
+
.btn.primary:active{background:var(--accent-pressed)}
|
|
49
|
+
.btn.sm{min-height:2rem;padding:.25rem .75rem;font-size:.84375rem}
|
|
50
|
+
.btn.lg{min-height:3rem;padding:.5rem 1.375rem}
|
|
51
|
+
.btn.wide{width:100%}
|
|
52
|
+
.btn:disabled,.btn[aria-disabled=true]{opacity:.4;cursor:default;pointer-events:none}
|
|
53
|
+
.field{display:flex;flex-direction:column;gap:.375rem}
|
|
54
|
+
label{width:fit-content;font-size:.8125rem;line-height:1.2308;font-weight:500}
|
|
55
|
+
input[type=text]{width:100%;min-width:0;height:3rem;padding:0 .875rem;background:var(--surface);color:var(--text);border:1px solid var(--line-strong);border-radius:8px;font:400 .9375rem/1.5 var(--mono)}
|
|
56
|
+
input[type=text]:focus{outline:2px solid var(--focus);outline-offset:2px}
|
|
57
|
+
input[type=text][aria-invalid=true]{border-color:var(--danger-line)}
|
|
58
|
+
form{display:flex;flex-direction:column;gap:.75rem}
|
|
59
|
+
.err{display:none;align-items:flex-start;gap:.375rem;color:var(--danger-fg);font-size:.84375rem;line-height:1.4815}
|
|
60
|
+
.err.on{display:flex}
|
|
61
|
+
.err .ic{margin-top:.125rem}
|
|
62
|
+
.alert{display:flex;flex-wrap:wrap;align-items:flex-start;gap:.75rem;padding:.75rem .875rem;border-radius:8px;background:var(--warning-bg);font-size:.84375rem;line-height:1.4815}
|
|
63
|
+
.alert>.ic{width:1.125rem;height:1.125rem;margin-top:1px;color:var(--warning-fg)}
|
|
64
|
+
.alert .text{flex:1 1 12rem;min-width:0}
|
|
65
|
+
.alert strong{display:block;font-weight:600}
|
|
66
|
+
.alert .act{flex:none;align-self:center}
|
|
67
|
+
.codebox{display:flex;flex-wrap:wrap;align-items:center;gap:.75rem;padding:1rem;border-radius:12px;background:var(--sunken)}
|
|
68
|
+
.code{flex:1 1 auto;min-width:0;font:600 clamp(1.25rem,7vw,1.75rem)/1.2143 var(--mono);letter-spacing:.18em;overflow-wrap:anywhere}
|
|
69
|
+
.code.expired{color:var(--disabled);text-decoration:line-through}
|
|
70
|
+
.badge{display:inline-flex;align-items:center;gap:.375rem;height:1.25rem;padding:0 .375rem;border-radius:6px;background:var(--danger-bg);color:var(--danger-fg);font-size:.8125rem;font-weight:500;white-space:nowrap}
|
|
71
|
+
.badge::before{content:"";width:.375rem;height:.375rem;border-radius:9999px;background:currentColor}
|
|
72
|
+
.wait{display:flex;align-items:center;gap:.75rem;padding:.75rem 1rem;border-radius:12px;background:var(--zone)}
|
|
73
|
+
.wait .spin{width:1rem;height:1rem;color:var(--accent-fg);fill:none;stroke:currentColor;stroke-width:3;stroke-linecap:round}
|
|
74
|
+
.wait .msg{flex:1;min-width:0;display:flex;flex-direction:column;font-size:.84375rem;line-height:1.4815}
|
|
75
|
+
.wait .msg b{font-weight:500}
|
|
76
|
+
.wait .msg span{color:var(--muted)}
|
|
77
|
+
.clock{display:flex;align-items:center;gap:.375rem;color:var(--muted);font-size:.84375rem;font-variant-numeric:tabular-nums}
|
|
78
|
+
.clock .ic{width:.875rem;height:.875rem}
|
|
79
|
+
.sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
|
|
80
|
+
.foot{flex:none;display:flex;justify-content:center;padding:0 1rem 2rem;color:var(--muted);font-size:.84375rem;line-height:1.4815;text-align:center}
|
|
81
|
+
.foot a{color:var(--text);text-underline-offset:2px}
|
|
82
|
+
.foot a:hover{color:var(--accent-fg)}
|
|
83
|
+
@media (prefers-reduced-motion:no-preference){.wait .spin{animation:spin 1s linear infinite}}
|
|
84
|
+
@keyframes spin{to{transform:rotate(360deg)}}
|
|
85
|
+
@media (min-width:40rem){.top{padding:0 1.5rem}main{padding:3.5rem 1rem}}
|
|
86
|
+
@media (max-width:30rem){.card{padding:1.25rem}.btn{padding-left:.875rem;padding-right:.875rem}#device-link{font-size:.84375rem}.steps>li{gap:.75rem}.alert .act{margin-left:1.875rem}}
|
|
87
|
+
`,q=`
|
|
12
88
|
(function(){
|
|
13
89
|
var cfg=JSON.parse(document.getElementById('cfg').textContent);
|
|
14
90
|
history.replaceState(null,'',location.pathname);
|
|
15
91
|
var auth={'Authorization':'Bearer '+cfg.handoff};
|
|
16
92
|
function back(status){var u=new URL(cfg.returnTo);u.searchParams.set('status',status);location.assign(u.toString());}
|
|
17
|
-
function
|
|
18
|
-
var error
|
|
93
|
+
function $(id){return document.getElementById(id);}
|
|
94
|
+
var error=$('error'),errorText=$('error-text');
|
|
95
|
+
function setError(msg){errorText.textContent=msg;error.className=msg?'err on':'err';}
|
|
19
96
|
if(cfg.kind==='anthropic'){
|
|
20
|
-
var form
|
|
97
|
+
var form=$('paste'),input=form.elements.code;
|
|
21
98
|
form.addEventListener('submit',function(e){
|
|
22
99
|
e.preventDefault();
|
|
23
|
-
var button=form.querySelector('button');button.disabled=true;
|
|
24
|
-
|
|
100
|
+
var button=form.querySelector('button');button.disabled=true;setError('');input.removeAttribute('aria-invalid');
|
|
101
|
+
function reject(msg){
|
|
102
|
+
setError(msg);input.setAttribute('aria-invalid','true');button.disabled=false;
|
|
103
|
+
var pre=document.querySelectorAll('[data-pre]');for(var i=0;i<pre.length;i++)pre[i].classList.add('done');
|
|
104
|
+
input.focus();
|
|
105
|
+
}
|
|
106
|
+
fetch(cfg.base,{method:'POST',headers:Object.assign({'Content-Type':'application/json'},auth),body:JSON.stringify({input:input.value})})
|
|
25
107
|
.then(function(r){return r.json().then(function(b){return {ok:r.ok,s:r.status,b:b};});})
|
|
26
108
|
.then(function(x){
|
|
27
109
|
if(x.ok){back(x.b.status==='connected'?'connected':'failed');return;}
|
|
28
110
|
if(x.s===401||x.s===404){back('failed');return;}
|
|
29
|
-
|
|
111
|
+
reject((x.b&&x.b.error&&x.b.error.message)||'That code was not accepted.');
|
|
30
112
|
})
|
|
31
|
-
.catch(function(){
|
|
113
|
+
.catch(function(){reject('Could not reach your runtime. Try again.');});
|
|
32
114
|
});
|
|
33
115
|
}else{
|
|
34
|
-
|
|
35
|
-
|
|
116
|
+
var copyLabel=$('copy-label');
|
|
117
|
+
$('copy').addEventListener('click',function(){
|
|
118
|
+
function done(){copyLabel.textContent='Copied';setTimeout(function(){copyLabel.textContent='Copy';},2000);}
|
|
119
|
+
if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(cfg.userCode).then(done,function(){});return;}
|
|
120
|
+
var r=document.createRange();r.selectNodeContents($('user-code'));var s=getSelection();s.removeAllRanges();s.addRange(r);
|
|
121
|
+
});
|
|
122
|
+
$('renew').addEventListener('click',function(){back('failed');});
|
|
123
|
+
var deadline=Date.now()+cfg.remainingSeconds*1000,left=$('left'),said=-1,timer;
|
|
124
|
+
function tick(){
|
|
125
|
+
var s=Math.max(0,Math.ceil((deadline-Date.now())/1000));
|
|
126
|
+
left.textContent=Math.floor(s/60)+':'+('0'+(s%60)).slice(-2);
|
|
127
|
+
var m=Math.ceil(s/60);
|
|
128
|
+
if(m!==said){said=m;$('left-live').textContent='Code expires in '+m+(m===1?' minute':' minutes');}
|
|
129
|
+
}
|
|
130
|
+
tick();timer=setInterval(tick,1000);
|
|
131
|
+
function expire(){
|
|
132
|
+
clearInterval(timer);
|
|
133
|
+
$('user-code').className='code expired';$('copy').hidden=true;$('expired-badge').hidden=false;
|
|
134
|
+
var link=$('device-link');link.removeAttribute('href');link.setAttribute('aria-disabled','true');
|
|
135
|
+
$('settings').hidden=true;$('waiting').hidden=true;$('expired').hidden=false;
|
|
136
|
+
}
|
|
36
137
|
(function poll(){
|
|
37
138
|
fetch(cfg.base+'/wait',{headers:auth})
|
|
38
139
|
.then(function(r){if(r.status===401||r.status===404)return {status:'failed'};if(!r.ok)throw new Error(String(r.status));return r.json();})
|
|
39
140
|
.then(function(b){
|
|
40
141
|
if(b.status==='pending'){poll();return;}
|
|
41
142
|
if(b.status==='connected'){back('connected');return;}
|
|
42
|
-
if(b.status==='expired'){
|
|
143
|
+
if(b.status==='expired'){expire();return;}
|
|
43
144
|
back('failed');
|
|
44
145
|
})
|
|
45
146
|
.catch(function(){setTimeout(poll,3000);});
|
|
46
147
|
})();
|
|
47
148
|
}
|
|
48
149
|
})();
|
|
49
|
-
|
|
150
|
+
`,F={arrow:'<path d="M7 7h10v10"/><path d="M7 17 17 7"/>',copy:'<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',clock:'<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>',warn:'<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/>',alert:'<circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/>',check:'<path d="M20 6 9 18l-5-5"/>'};function c(e,t=""){return`<svg class="ic${t}" viewBox="0 0 24 24" aria-hidden="true" focusable="false">${F[e]}</svg>`}a(c,"icon");const W='<svg viewBox="0 0 32 32" aria-hidden="true" focusable="false"><path d="M23.4 8.6A10.5 10.5 0 1 0 23.4 23.4" fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round"/><path d="M16 16 L27.5 16" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/><circle cx="16" cy="16" r="3.6" fill="currentColor"/><circle cx="27.5" cy="16" r="3.2" fill="currentColor"/></svg>',V={claude:'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect width="24" height="24" fill="#d97757"/><path d="M12 5v14M5 12h14M7 7l10 10M17 7 7 17" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg>',chatgpt:'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect width="24" height="24" fill="#141816"/><circle cx="12" cy="12" r="5.5" fill="none" stroke="#fff" stroke-width="1.8"/></svg>'},S="team@northlight.ai";function T(e){const t=JSON.stringify(e.config).replace(/</g,"\\u003c");return`<!doctype html>
|
|
50
151
|
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
51
|
-
<
|
|
52
|
-
<
|
|
152
|
+
<meta name="color-scheme" content="light dark">
|
|
153
|
+
<title>${p(e.title)}</title><style nonce="${e.nonce}">${D}</style></head>
|
|
154
|
+
<body>
|
|
155
|
+
<header class="top">${W}<span>Northlight</span></header>
|
|
156
|
+
<main><div class="col">${e.body}</div></main>
|
|
157
|
+
<footer class="foot"><span>Need help? Email <a href="mailto:${S}">${S}</a></span></footer>
|
|
53
158
|
<script type="application/json" id="cfg">${t}<\/script>
|
|
54
|
-
<script nonce="${e.nonce}">${
|
|
55
|
-
</body></html>`}a(
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
<
|
|
62
|
-
<
|
|
63
|
-
|
|
64
|
-
<
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
<
|
|
70
|
-
<
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<
|
|
159
|
+
<script nonce="${e.nonce}">${q}<\/script>
|
|
160
|
+
</body></html>`}a(T,"page");function M(e,t){return`<div class="head"><div class="logo">${V[e]}</div><div><span class="eyebrow">AI subscription</span><h1>Connect your ${t} account</h1></div></div>`}a(M,"header");function f(e,t,n="",r=""){return`<li${r}><span class="n"><span>${e}</span>${c("check")}</span><div class="body"><span class="title">${t}</span>${n}</div></li>`}a(f,"step");function X(e,t,n,r){return T({nonce:t,title:"Connect Claude",body:`<div class="card">
|
|
161
|
+
${M("claude","Claude")}
|
|
162
|
+
<ol class="steps">
|
|
163
|
+
${f(1,"Sign in to Claude in a new tab",`<div><a class="btn" href="${p(e.url)}" target="_blank" rel="noopener noreferrer">Open claude.ai${c("arrow")}</a></div>`," data-pre")}
|
|
164
|
+
${f(2,"Copy the code Claude shows you",""," data-pre")}
|
|
165
|
+
${f(3,"Paste it here",`<form id="paste" autocomplete="off">
|
|
166
|
+
<div class="field"><label for="code">Code from Claude</label>
|
|
167
|
+
<input type="text" id="code" name="code" required spellcheck="false" autocapitalize="off" aria-describedby="error">
|
|
168
|
+
<div id="error" class="err" role="alert">${c("alert")}<span id="error-text"></span></div></div>
|
|
169
|
+
<button class="btn primary lg wide" type="submit">Connect Claude</button>
|
|
170
|
+
</form>`)}
|
|
171
|
+
</ol>
|
|
172
|
+
</div>`,config:{kind:"anthropic",base:`${l}/${encodeURIComponent(e.flow_id)}`,returnTo:n,handoff:r}})}a(X,"anthropicPage");function Y(e,t){const n=Date.parse(e.expires_at)-t;return Math.max(0,Math.floor(Math.min(Number.isNaN(n)?$*1e3:n,$*1e3)/1e3))}a(Y,"codeSecondsLeft");function K(e,t,n,r,o=Date.now()){const i=e.user_code??"";return T({nonce:t,title:"Connect ChatGPT",body:`<div class="card">
|
|
173
|
+
${M("chatgpt","ChatGPT")}
|
|
174
|
+
<div class="alert" id="settings" role="alert">${c("warn")}
|
|
175
|
+
<div class="text"><strong>Turn on device code sign-in first</strong>OpenAI refuses this sign-in unless device code authorization for Codex is on in ChatGPT's Security settings.</div>
|
|
176
|
+
<div class="act"><a class="btn sm" href="${G}" target="_blank" rel="noopener noreferrer">Open settings${c("arrow")}</a></div></div>
|
|
177
|
+
<ol class="steps" id="device">
|
|
178
|
+
${f(1,"Open the OpenAI device page",`<div><a class="btn" id="device-link" href="${p(e.url)}" target="_blank" rel="noopener noreferrer">${p(e.url.replace(/^https:\/\//,""))}${c("arrow")}</a></div>`)}
|
|
179
|
+
${f(2,"Enter this code",`<div class="codebox"><span class="code" id="user-code">${p(i)}</span>
|
|
180
|
+
<span class="badge" id="expired-badge" hidden>Expired</span>
|
|
181
|
+
<button class="btn sm" type="button" id="copy">${c("copy")}<span id="copy-label">Copy</span></button></div>`)}
|
|
182
|
+
${f(3,"Approve the sign-in",`<span class="small">When OpenAI shows an account email, check it's the account you want to use: approving connects that account.</span>`)}
|
|
183
|
+
</ol>
|
|
184
|
+
<div class="wait" id="waiting">
|
|
185
|
+
<svg class="spin" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M21 12a9 9 0 1 1-9-9"/></svg>
|
|
186
|
+
<div class="msg" aria-live="polite"><b>Waiting for your approval at OpenAI</b><span>This page moves on by itself.</span></div>
|
|
187
|
+
<div class="clock">${c("clock")}<span id="left" aria-hidden="true"></span><span class="sr" id="left-live" aria-live="polite"></span></div>
|
|
76
188
|
</div>
|
|
77
|
-
<
|
|
189
|
+
<div class="alert" id="expired" role="alert" hidden>${c("warn")}
|
|
190
|
+
<div class="text"><strong>The code expired before it was approved</strong>Codes last 15 minutes. Getting a new one starts the sign-in over.</div>
|
|
191
|
+
<div class="act"><button class="btn primary sm" type="button" id="renew">Get a new code</button></div></div>
|
|
192
|
+
</div>`,config:{kind:"openai",base:`${l}/${encodeURIComponent(e.flow_id)}`,returnTo:n,handoff:r,userCode:i,expiresAt:e.expires_at,remainingSeconds:Y(e,o)}})}a(K,"openaiPage");async function Q(e,t,n,r){const o=x(n.searchParams,"handoff"),i=await C(r,o);if(y(i.jti))throw u();const s=x(n.searchParams,"return_to");let b;try{b=s===void 0?void 0:new URL(s).origin}catch{b=void 0}if(s===void 0||b!==new URL(r.issuer).origin)throw new d(400,"invalid_request","return_to must be an absolute URL on the directory origin","return_to");const g=x(n.searchParams,"vendor");if(g!=="anthropic"&&g!=="openai")throw new d(400,"invalid_request","vendor must be anthropic or openai","vendor");if(!z(i.jti,i.exp))throw u();let v;try{v=await P({provider:N(g),jti:i.jti})}catch(w){console.error("[vendor-signin] start failed:",w instanceof Error?w.message:w),t.writeHead(303,{Location:H(s,"failed"),"Cache-Control":"no-store","Referrer-Policy":"no-referrer"}),t.end();return}const m=j(16).toString("base64"),A=g==="anthropic"?X(v,m,s,o):K(v,m,s,o);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","X-Content-Type-Options":"nosniff","Content-Security-Policy":`default-src 'none'; script-src 'nonce-${m}'; style-src 'nonce-${m}'; connect-src 'self'; form-action 'none'; base-uri 'none'; frame-ancestors 'none'`}),t.end(A)}a(Q,"startPage");async function _(e,t,n){const r=await C(t,U(e)),o=k(n);if(!o){if(y(r.jti))return!1;throw u()}if(o.jti===void 0||o.jti!==r.jti)throw u();return!0}a(_,"followUpFlow");async function Z(e,t,n,r){if(!await _(e,n,r)){h(t,200,{status:"failed"});return}const o=await J(e);try{await I(r,o.input),h(t,200,{status:"connected"})}catch(i){const s=k(r);if(s&&s.status!=="pending"){h(t,200,{status:"failed"});return}throw i}}a(Z,"submitCode");async function ee(e,t,n,r){if(!await _(e,n,r)){h(t,200,{status:"failed"});return}const o=new AbortController;t.once("close",()=>o.abort());const i=await L(r,B,o.signal);h(t,200,{status:i?.status??"failed"})}a(ee,"waitFlow");async function de(e,t,n,r){const o=e.method??"GET";if(n.pathname===l&&o==="GET"){await Q(e,t,n,r);return}const i=n.pathname.slice(l.length+1).split("/");let s="";try{s=i[0]?decodeURIComponent(i[0]):""}catch{throw new d(404,"not_found","unknown operation")}if(s&&i.length===1&&o==="POST"){await Z(e,t,r,s);return}if(s&&i.length===2&&i[1]==="wait"&&o==="GET"){await ee(e,t,r,s);return}throw new d(404,"not_found","unknown operation")}a(de,"handleVendorSignIn");export{l as VENDOR_SIGNIN_PATH,X as anthropicPage,de as handleVendorSignIn,ce as isVendorSignInPath,K as openaiPage};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.421",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
},
|
|
135
135
|
"license": "UNLICENSED",
|
|
136
136
|
"dependencies": {
|
|
137
|
-
"@north-light/identity": "0.3.
|
|
137
|
+
"@north-light/identity": "0.3.421",
|
|
138
138
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
139
139
|
"@earendil-works/pi-ai": "1.1.0",
|
|
140
140
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.421",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.421",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@earendil-works/pi-ai": "1.1.0",
|
|
19
19
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
20
20
|
"@earendil-works/pi-tui": "1.1.0",
|
|
21
|
-
"@north-light/identity": "0.3.
|
|
21
|
+
"@north-light/identity": "0.3.421",
|
|
22
22
|
"cron-parser": "^5.6.0",
|
|
23
23
|
"esbuild": "^0.27.7",
|
|
24
24
|
"jose": "^6.2.12",
|
|
@@ -12095,17 +12095,17 @@
|
|
|
12095
12095
|
},
|
|
12096
12096
|
"packages/crouter-api": {
|
|
12097
12097
|
"name": "@north-light/api",
|
|
12098
|
-
"version": "0.3.
|
|
12098
|
+
"version": "0.3.421",
|
|
12099
12099
|
"license": "UNLICENSED"
|
|
12100
12100
|
},
|
|
12101
12101
|
"packages/crouter-env-docker": {
|
|
12102
12102
|
"name": "@north-light/env-docker",
|
|
12103
|
-
"version": "0.3.
|
|
12103
|
+
"version": "0.3.421",
|
|
12104
12104
|
"license": "UNLICENSED"
|
|
12105
12105
|
},
|
|
12106
12106
|
"packages/crouter-identity": {
|
|
12107
12107
|
"name": "@north-light/identity",
|
|
12108
|
-
"version": "0.3.
|
|
12108
|
+
"version": "0.3.421",
|
|
12109
12109
|
"license": "UNLICENSED",
|
|
12110
12110
|
"dependencies": {
|
|
12111
12111
|
"jose": "^6.2.1"
|
|
@@ -12113,20 +12113,20 @@
|
|
|
12113
12113
|
},
|
|
12114
12114
|
"packages/crouter-plugin": {
|
|
12115
12115
|
"name": "@north-light/plugin",
|
|
12116
|
-
"version": "0.3.
|
|
12116
|
+
"version": "0.3.421",
|
|
12117
12117
|
"license": "UNLICENSED",
|
|
12118
12118
|
"dependencies": {
|
|
12119
|
-
"@north-light/api": "0.3.
|
|
12120
|
-
"@north-light/identity": "0.3.
|
|
12119
|
+
"@north-light/api": "0.3.421",
|
|
12120
|
+
"@north-light/identity": "0.3.421"
|
|
12121
12121
|
}
|
|
12122
12122
|
},
|
|
12123
12123
|
"packages/crouter-sdk": {
|
|
12124
12124
|
"name": "@north-light/sdk",
|
|
12125
|
-
"version": "0.3.
|
|
12125
|
+
"version": "0.3.421",
|
|
12126
12126
|
"license": "UNLICENSED",
|
|
12127
12127
|
"dependencies": {
|
|
12128
|
-
"@north-light/api": "0.3.
|
|
12129
|
-
"@north-light/identity": "0.3.
|
|
12128
|
+
"@north-light/api": "0.3.421",
|
|
12129
|
+
"@north-light/identity": "0.3.421",
|
|
12130
12130
|
"jose": "^6.2.1"
|
|
12131
12131
|
},
|
|
12132
12132
|
"bin": {
|