@ycodium-ai/agent-codex 0.2.2167 → 0.2.2510

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
@@ -17,7 +17,14 @@ Facts:
17
17
  - Manifest permission is `{ kind: "executor" }`.
18
18
  - `runtimeModeSwitch` is `next-turn` (same table the host adapter reads).
19
19
  - `sessionModelSwitch` is `in-session`.
20
- - Native ChatGPT device-code login is supported (`supportsNativeSubscription`).
20
+ - Native ChatGPT device-code login is supported: `deviceCodeSignInArgs` runs
21
+ `codex login --device-auth`.
22
+ - Account section UI: the add-provider dialog and the provider detail page draw
23
+ this plugin's own account section (`src/ui/`, bundled to `assets/ui.js`) through the host's
24
+ provider settings slot, declared in `package.json#ycodium.ui.providerSettings`. It
25
+ covers choosing an account already on the machine, ChatGPT sign-in, API URL and
26
+ key, and the separate shadow directory a second account gets. The UI uses the
27
+ host's React and `@ycodium-ai/plugin-api/provider-settings`.
21
28
 
22
29
  Develop with `vp run --filter @ycodium-ai/agent-codex typecheck`, `build`, and `test`.
23
30
 
package/assets/ui.js ADDED
@@ -0,0 +1,79 @@
1
+ var Q=window.__ycodiumPluginHost.modules?.["@ycodium-ai/plugin-api/provider-settings"];if(!Q)throw new Error("This plugin needs a newer Ycodium app. Update the app.");var{PROVIDER_SETTINGS_VIEW_CAPABILITY:Z,accountDirectoryCandidates:ee,accountDirectorySlug:Ye,accountProbeHasSignedInAccount:te,allocateAccountDirectory:ne,providerInstanceAccountPaths:oe}=Q;var ke=window.__ycodiumPluginHost.react;var{Activity:Xe,Children:je,Component:ze,Fragment:$e,Profiler:qe,PureComponent:Ge,StrictMode:We,Suspense:Je,__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE:Qe,__COMPILER_RUNTIME:Ze,act:et,cache:tt,cacheSignal:nt,captureOwnerStack:ot,cloneElement:rt,createContext:re,createElement:ae,createRef:at,forwardRef:it,isValidElement:ct,lazy:st,memo:dt,startTransition:ut,unstable_useCacheRefresh:lt,use:pt,useActionState:gt,useCallback:mt,useContext:ie,useDebugValue:ft,useDeferredValue:yt,useEffect:A,useEffectEvent:ht,useId:Pt,useImperativeHandle:wt,useInsertionEffect:xt,useLayoutEffect:vt,useMemo:St,useOptimistic:At,useReducer:Ct,useRef:m,useState:K,useSyncExternalStore:bt,useTransition:It,version:Nt}=ke;var ce=re(null),se=ce.Provider;function h(){let e=ie(ce);if(e===null)throw new Error("Codex UI has not been registered.");return e}var x="YCODIUM_CODEX_API_KEY";var B={configKeys:["shadowHomePath","homePath"],defaultDirectory:"~/.codex"},M="account",k="codex",He="Codex";function u(e,t){if(e===null||typeof e!="object")return"";let r=e[t];return typeof r=="string"?r:""}function f(e){let t=u(e.config,"authMode");return t==="chatgpt"||t==="apiKey"?t:"default"}function H(e){return e.displayName?.trim()||He}function de(e){if(f(e)!=="apiKey")return!0;try{let t=new URL(u(e.config,"apiBaseUrl"));if(t.protocol!=="https:"&&t.protocol!=="http:")return!1}catch{return!1}return e.environment.some(t=>t.name===x&&(t.valueRedacted===!0||t.value.trim().length>0))}function v(e){if(f(e)!=="chatgpt")return null;let t=e.config;if(t.shadowHomePath!=="")return null;let r=u(t,"homePath");return r.length>0?r:null}function ue(e){return f(e)==="chatgpt"&&v(e)===null}function le(e){return{config:{homePath:e,shadowHomePath:"",authMode:"chatgpt"}}}function pe(e,t,r){let a=r==="add"?v(e):null;return t==="apiKey"&&a!==null?{config:{authMode:t,homePath:void 0,shadowHomePath:void 0}}:{config:{authMode:t}}}function ge(){return{config:{authMode:"chatgpt",shadowHomePath:void 0}}}function Oe(e){return u(e.config,"shadowHomePath").trim().length===0}async function me(e){let t=e.siblings.filter(o=>o.instance.driver===k).filter(o=>f(o.instance)!=="apiKey").map(o=>({id:o.instanceId,path:u(o.instance.config,"shadowHomePath")||u(o.instance.config,"homePath")})),r=[...new Set(["",...t.map(o=>o.path)])],a=await e.probe(r),c=new Map(t.flatMap(({id:o,path:l})=>{let S=a[r.indexOf(l)];return S?[[S.accountPath,o]]:[]}));return{probes:[...new Map(a.map(o=>[o.accountPath,o])).values()],configuredPaths:c,defaultAccount:a[0]??null}}function fe(e){return e.filter(t=>t.authType!=="apiKey"&&(t.state==="signed-in"||t.state==="expired"))}function ye(e){return{none:e.every(r=>r.state==="signed-out"||r.authType==="apiKey")?e.length===0?"detectFailed":"noAccounts":null,unreadable:e.some(r=>r.state==="unreadable")}}async function he(e){let t=oe(e.instances,k,B),r=ee({displayName:e.displayName,taken:t,rule:B}),c=(await e.probe([...t,...r])).slice(t.length).findIndex(o=>!o.directoryExists);return c<0?void 0:r[c]}function O(e){return ne({driver:k,displayName:e.displayName,instances:e.instances,rule:B,probe:e.probe})}function Pe(e){let t=f(e);return(t==="chatgpt"||t==="apiKey")&&v(e)===null&&Oe(e)}async function we(e,t){let r=u(e.config,"shadowHomePath").trim();if(r.length===0)return!0;let[a]=await t([r]);return a!==void 0&&a.authType!=="apiKey"&&te(a)}function xe(e,t){if(e!==null)return t.find(r=>r.authEmail===e)}function y(e){return(t=>ae(h().ui[e],{...t,className:`ycodium-codex-ui ${typeof t.className=="string"?t.className:""}`}))}var C=y("Button"),U=y("DraftInput"),ve=y("Select"),b=y("SelectItem"),Se=y("SelectPopup"),Ae=y("SelectTrigger"),Ce=y("SelectValue");function be(){let e=h().i18n.usePluginTranslation();return{t:(t,r)=>e(t,r)}}var{jsx:i,jsxs:s,Fragment:Ie}=window.__ycodiumPluginHost.jsxRuntime;function Ne(e){let{t}=be(),r=h(),{placement:a,instance:c}=e,o=m(e);o.current=e;let[l,S]=K(null),[P,L]=K(!1),I=m(!1),N=m(!1),V=m(null),w=m(0),p=f(c),Te=v(c),Y=H(c),E=()=>[...o.current.siblings.map(n=>n.instance),...o.current.placement==="edit"?[o.current.instance]:[]],F=()=>r.notify(t("account.directoryUnavailable"),"error"),Re=n=>{V.current=n.length>0?n:null,o.current.onChange({config:{shadowHomePath:n.length>0?n:void 0}})},X=n=>{let d=++w.current;he({displayName:n,instances:E(),probe:o.current.probeAccount}).then(g=>{d===w.current&&(g!==void 0?Re(g):F())})},j=async()=>{if(!I.current){I.current=!0,L(!0);try{let n=await me({siblings:o.current.siblings,probe:o.current.probeAccount});S({probes:n.probes,configuredPaths:n.configuredPaths})}finally{L(!1),I.current=!1}}};A(()=>{a==="add"&&e.active&&j()},[a,e.active]);let z=m(c.displayName?.trim()??"");A(()=>{let n=c.displayName?.trim()??"",d=z.current;z.current=n,!(a!=="add"||!N.current)&&(n.length===0||n===d||u(o.current.instance.config,"shadowHomePath")===(V.current??"")&&X(n))},[c.displayName,a]);let $=a==="edit"?xe(e.authEmail,e.siblings):void 0,T=de(c),R=a==="add"&&ue(c),q=a==="edit"&&p==="apiKey",G=$===void 0?void 0:t("account.duplicate",{name:$.displayName}),W=R?t("account.addAndSignIn"):void 0,{onReport:J}=e;A(()=>{J({complete:T,submitLabel:W,signInAfterAdd:R,hidesSignIn:q,notice:G,prepare:async n=>{if(!Pe(n))return null;let d=await O({displayName:H(n),instances:E(),probe:o.current.probeAccount});if(d===void 0)throw new Error(t("account.directoryUnavailable"));return{config:{shadowHomePath:d}}}})},[J,T,W,R,q,G]);let _e=n=>{if(n!==p){if(w.current+=1,!(a==="edit"&&n==="apiKey")){e.onChange(pe(c,n,a));return}(async()=>{let d=await we(c,o.current.probeAccount),g;d&&(g=await O({displayName:Y,instances:E(),probe:o.current.probeAccount}),g===void 0&&F()),o.current.onChange({config:{authMode:"apiKey",...g===void 0?{}:{shadowHomePath:g}}})})()}},De=n=>{w.current+=1;let d=l?.configuredPaths.get(n.accountPath);if(d!==void 0){e.openInstance(d);return}N.current=!1,e.onChange(le(n.accountPath))},Ke=()=>{w.current+=1,N.current=!0,e.onChange(ge()),X(Y)},_=l===null?null:ye(l.probes),Be=a==="add"&&p!=="apiKey"?s("div",{className:"grid gap-2","aria-busy":P,children:[P?i("p",{className:"text-xs text-muted-foreground",children:t("account.detecting")}):null,!P&&_?.none!=null?i("p",{className:"text-xs text-muted-foreground",children:t(`account.${_.none}`)}):null,l!==null?fe(l.probes).map(n=>s(C,{variant:"outline","aria-pressed":Te===n.accountPath,onClick:()=>De(n),children:[n.email===void 0?t("account.existing"):t("account.useAccount",{email:n.email}),l.configuredPaths.has(n.accountPath)?` \xB7 ${t("account.alreadyAdded")}`:""]},n.accountPath)):null,!P&&_?.unreadable===!0?i("p",{className:"text-xs text-muted-foreground",children:t("account.detectFailed")}):null,i(C,{variant:"outline",onClick:Ke,children:t("account.addAnother")}),i(C,{size:"xs",variant:"ghost",disabled:P,onClick:()=>{j()},children:t("account.retry")})]}):null,D=c.environment.find(n=>n.name===x),Me=s("div",{className:"grid gap-3",children:[s("label",{className:"grid gap-1",children:[i("span",{className:"text-xs font-medium",children:t("account.method")}),s(ve,{value:p,onValueChange:n=>_e(Ue(n)),children:[i(Ae,{"aria-label":t("account.method"),children:i(Ce,{children:t(p==="apiKey"?"account.apiKey":p==="chatgpt"?"account.chatgpt":"account.existing")})}),s(Se,{children:[i(b,{value:"default",children:t("account.existing")}),i(b,{value:"chatgpt",children:t("account.chatgpt")}),i(b,{value:"apiKey",children:t("account.apiKey")})]})]})]}),p==="apiKey"?s(Ie,{children:[s("label",{className:"grid gap-1",children:[i("span",{className:"text-xs font-medium",children:t("account.url")}),i(U,{value:u(c.config,"apiBaseUrl"),onCommit:n=>e.onChange({config:{apiBaseUrl:n.trim()}}),spellCheck:!1,"aria-label":t("account.url")})]}),s("label",{className:"grid gap-1",children:[i("span",{className:"text-xs font-medium",children:t("account.key")}),i(U,{value:D?.valueRedacted===!0?"":D?.value??"",type:"password",autoComplete:"off",spellCheck:!1,"aria-label":t("account.key"),placeholder:D?.valueRedacted===!0?t("account.keyStoredPlaceholder"):void 0,onCommit:n=>e.onChange({environment:[{name:x,value:n,sensitive:!0}]})})]}),T?null:i("p",{className:"text-xs text-muted-foreground",children:t("account.apiRequired")})]}):i("p",{className:"text-xs text-muted-foreground",children:t("account.loginHint")})]});return s("div",{className:"ycodium-codex-ui grid gap-6",children:[Be,Me]})}function Ue(e){return e==="chatgpt"||e==="apiKey"?e:"default"}var Ee=`/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
2
+ @layer properties;
3
+ @scope (.ycodium-codex-ui) {
4
+ .container:where(:scope, *) {
5
+ width: 100%;
6
+ @media (width >= 40rem) {
7
+ max-width: 40rem;
8
+ }
9
+ @media (width >= 48rem) {
10
+ max-width: 48rem;
11
+ }
12
+ @media (width >= 64rem) {
13
+ max-width: 64rem;
14
+ }
15
+ @media (width >= 80rem) {
16
+ max-width: 80rem;
17
+ }
18
+ @media (width >= 96rem) {
19
+ max-width: 96rem;
20
+ }
21
+ }
22
+ .grid:where(:scope, *) {
23
+ display: grid;
24
+ }
25
+ .gap-1:where(:scope, *) {
26
+ gap: calc(var(--spacing, 0.25rem) * 1);
27
+ }
28
+ .gap-2:where(:scope, *) {
29
+ gap: calc(var(--spacing, 0.25rem) * 2);
30
+ }
31
+ .gap-3:where(:scope, *) {
32
+ gap: calc(var(--spacing, 0.25rem) * 3);
33
+ }
34
+ .gap-6:where(:scope, *) {
35
+ gap: calc(var(--spacing, 0.25rem) * 6);
36
+ }
37
+ .text-xs:where(:scope, *) {
38
+ font-size: var(--text-xs, 0.75rem);
39
+ line-height: var(--tw-leading, var(--text-xs--line-height, calc(1 / 0.75)));
40
+ }
41
+ .font-medium:where(:scope, *) {
42
+ --tw-font-weight: var(--font-weight-medium, 500);
43
+ font-weight: var(--font-weight-medium, 500);
44
+ }
45
+ .text-muted-foreground:where(:scope, *) {
46
+ color: var(--contrast-muted-foreground);
47
+ }
48
+ .shadow:where(:scope, *) {
49
+ --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
50
+ box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
51
+ }
52
+ .outline:where(:scope, *) {
53
+ outline-style: var(--tw-outline-style);
54
+ outline-width: 1px;
55
+ }
56
+ }
57
+ @layer properties {
58
+ @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
59
+ *, ::before, ::after, ::backdrop {
60
+ --tw-font-weight: initial;
61
+ --tw-shadow: 0 0 #0000;
62
+ --tw-shadow-color: initial;
63
+ --tw-shadow-alpha: 100%;
64
+ --tw-inset-shadow: 0 0 #0000;
65
+ --tw-inset-shadow-color: initial;
66
+ --tw-inset-shadow-alpha: 100%;
67
+ --tw-ring-color: initial;
68
+ --tw-ring-shadow: 0 0 #0000;
69
+ --tw-inset-ring-color: initial;
70
+ --tw-inset-ring-shadow: 0 0 #0000;
71
+ --tw-ring-inset: initial;
72
+ --tw-ring-offset-width: 0px;
73
+ --tw-ring-offset-color: #fff;
74
+ --tw-ring-offset-shadow: 0 0 #0000;
75
+ --tw-outline-style: solid;
76
+ }
77
+ }
78
+ }
79
+ `;function Ve(e){let t=r=>s(se,{value:e,children:[i("style",{children:Ee}),i(Ne,{...r})]});return{pages:{},panels:{},views:{[M]:t},viewCapabilities:{[M]:[Z]}}}export{Ve as default};