@ycodium-ai/agent-codex 0.2.2488 → 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 +6 -0
- package/assets/ui.js +79 -0
- package/dist/index.js +62 -15
- package/locales/en.json +21 -0
- package/locales/zh-CN.json +21 -0
- package/package.json +33 -5
package/README.md
CHANGED
|
@@ -19,6 +19,12 @@ Facts:
|
|
|
19
19
|
- `sessionModelSwitch` is `in-session`.
|
|
20
20
|
- Native ChatGPT device-code login is supported: `deviceCodeSignInArgs` runs
|
|
21
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`.
|
|
22
28
|
|
|
23
29
|
Develop with `vp run --filter @ycodium-ai/agent-codex typecheck`, `build`, and `test`.
|
|
24
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};
|
package/dist/index.js
CHANGED
|
@@ -429,7 +429,11 @@ import { ExecutorSpawnRefusedError } from "@ycodium-ai/plugin-api/executor";
|
|
|
429
429
|
|
|
430
430
|
// src/config.ts
|
|
431
431
|
import { modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
|
|
432
|
+
|
|
433
|
+
// src/apiKeyEnv.ts
|
|
432
434
|
var CODEX_INSTANCE_API_KEY_ENV = "YCODIUM_CODEX_API_KEY";
|
|
435
|
+
|
|
436
|
+
// src/config.ts
|
|
433
437
|
var CODEX_INSTANCE_MODEL_PROVIDER = "ycodium_api";
|
|
434
438
|
function isRecord2(value) {
|
|
435
439
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -913,6 +917,28 @@ function jsonRpcErrorMessage(error) {
|
|
|
913
917
|
}
|
|
914
918
|
|
|
915
919
|
// src/rpc.ts
|
|
920
|
+
function createLineAssembler() {
|
|
921
|
+
const fragments = [];
|
|
922
|
+
return {
|
|
923
|
+
push: (text) => {
|
|
924
|
+
const lines = [];
|
|
925
|
+
let start = 0;
|
|
926
|
+
for (let newline = text.indexOf("\n"); newline !== -1; newline = text.indexOf("\n", start)) {
|
|
927
|
+
fragments.push(text.slice(start, newline));
|
|
928
|
+
lines.push(fragments.join(""));
|
|
929
|
+
fragments.length = 0;
|
|
930
|
+
start = newline + 1;
|
|
931
|
+
}
|
|
932
|
+
if (start < text.length) fragments.push(text.slice(start));
|
|
933
|
+
return lines;
|
|
934
|
+
},
|
|
935
|
+
end: () => {
|
|
936
|
+
const line = fragments.join("");
|
|
937
|
+
fragments.length = 0;
|
|
938
|
+
return line;
|
|
939
|
+
}
|
|
940
|
+
};
|
|
941
|
+
}
|
|
916
942
|
var STDERR_TAIL_LIMIT = 4e3;
|
|
917
943
|
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
918
944
|
var ANSI_ESCAPE_CHAR = String.fromCharCode(27);
|
|
@@ -980,17 +1006,12 @@ async function createCodexRpcClient(handle, handlers) {
|
|
|
980
1006
|
}
|
|
981
1007
|
};
|
|
982
1008
|
const pumpStdout = (async () => {
|
|
983
|
-
|
|
1009
|
+
const lines = createLineAssembler();
|
|
984
1010
|
for await (const chunk of handle.stdout) {
|
|
985
|
-
|
|
986
|
-
let index = buffer.indexOf("\n");
|
|
987
|
-
while (index >= 0) {
|
|
988
|
-
dispatch(buffer.slice(0, index));
|
|
989
|
-
buffer = buffer.slice(index + 1);
|
|
990
|
-
index = buffer.indexOf("\n");
|
|
991
|
-
}
|
|
1011
|
+
for (const line of lines.push(decoder.decode(chunk, { stream: true }))) dispatch(line);
|
|
992
1012
|
}
|
|
993
|
-
|
|
1013
|
+
const last = lines.end();
|
|
1014
|
+
if (last.length > 0) dispatch(last);
|
|
994
1015
|
})().catch(() => void 0);
|
|
995
1016
|
const pumpStderr = (async () => {
|
|
996
1017
|
const errorDecoder = new TextDecoder();
|
|
@@ -1455,7 +1476,7 @@ function turnCompletedControlFlow(params) {
|
|
|
1455
1476
|
const error = isRecord3(turn["error"]) ? trimText(turn["error"]["message"]) : void 0;
|
|
1456
1477
|
return error ? { state, errorMessage: error } : { state };
|
|
1457
1478
|
}
|
|
1458
|
-
function
|
|
1479
|
+
function fileChangeEntries(params) {
|
|
1459
1480
|
if (!isRecord3(params)) return [];
|
|
1460
1481
|
const item = isRecord3(params["item"]) ? params["item"] : params;
|
|
1461
1482
|
const changes = item["changes"] ?? item["fileChanges"] ?? params["fileChanges"];
|
|
@@ -1469,10 +1490,32 @@ function toApplyPatchFileChanges(params) {
|
|
|
1469
1490
|
if (!isRecord3(entry)) continue;
|
|
1470
1491
|
const path = asString(entry["path"]) ?? asString(entry["file"]);
|
|
1471
1492
|
if (!path) continue;
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1493
|
+
out.push({
|
|
1494
|
+
path,
|
|
1495
|
+
kind: (asString(entry["type"]) ?? asString(entry["kind"]) ?? "update").toLowerCase(),
|
|
1496
|
+
movePath: asString(entry["move_path"]) ?? asString(entry["movePath"]),
|
|
1497
|
+
diff: asString(entry["unified_diff"]) ?? asString(entry["unifiedDiff"]),
|
|
1498
|
+
content: asString(entry["content"])
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1501
|
+
return out;
|
|
1502
|
+
}
|
|
1503
|
+
var MAX_DESCRIBED_FILE_CHANGES = 20;
|
|
1504
|
+
function describeFileChanges(params) {
|
|
1505
|
+
const entries = fileChangeEntries(params).toSorted(
|
|
1506
|
+
(left, right) => left.path.localeCompare(right.path)
|
|
1507
|
+
);
|
|
1508
|
+
if (entries.length === 0) return void 0;
|
|
1509
|
+
const lines = entries.slice(0, MAX_DESCRIBED_FILE_CHANGES).map(
|
|
1510
|
+
(entry) => entry.movePath ? `${entry.kind} ${entry.path} -> ${entry.movePath}` : `${entry.kind} ${entry.path}`
|
|
1511
|
+
);
|
|
1512
|
+
const remaining = entries.length - lines.length;
|
|
1513
|
+
return remaining > 0 ? `${lines.join("\n")}
|
|
1514
|
+
+${remaining} more` : lines.join("\n");
|
|
1515
|
+
}
|
|
1516
|
+
function toApplyPatchFileChanges(params) {
|
|
1517
|
+
const out = [];
|
|
1518
|
+
for (const { path, kind, movePath, diff, content } of fileChangeEntries(params)) {
|
|
1476
1519
|
if (kind === "add") {
|
|
1477
1520
|
out.push({
|
|
1478
1521
|
path,
|
|
@@ -1728,8 +1771,10 @@ function describeFileChangeApproval(params) {
|
|
|
1728
1771
|
const reason = trimText(record["reason"]);
|
|
1729
1772
|
const grantRoot = asString(record["grantRoot"]);
|
|
1730
1773
|
const callId = asString(record["callId"]);
|
|
1774
|
+
const detail = reason ?? describeFileChanges(record) ?? trimText(grantRoot);
|
|
1731
1775
|
return {
|
|
1732
1776
|
...reason ? { reason } : {},
|
|
1777
|
+
...detail ? { detail } : {},
|
|
1733
1778
|
...grantRoot ? { grantRoot } : {},
|
|
1734
1779
|
...callId ? { callId } : {},
|
|
1735
1780
|
fileChanges: toApplyPatchFileChanges(record)
|
|
@@ -2390,7 +2435,7 @@ function mapServerRequestToEvents(input) {
|
|
|
2390
2435
|
payload["args"] = input.params;
|
|
2391
2436
|
} else if (input.method === "item/fileChange/requestApproval" || input.method.includes("applyPatch")) {
|
|
2392
2437
|
const described = describeFileChangeApproval(input.params);
|
|
2393
|
-
if (described.
|
|
2438
|
+
if (described.detail) payload["detail"] = described.detail;
|
|
2394
2439
|
if (described.fileChanges.length > 0) payload["fileChanges"] = described.fileChanges;
|
|
2395
2440
|
payload["args"] = {
|
|
2396
2441
|
...described.callId ? { callId: described.callId } : {},
|
|
@@ -4409,6 +4454,8 @@ var createCodexInstance = (config, host, attachments) => {
|
|
|
4409
4454
|
...CODEX_NATIVE_MODE_REPORT
|
|
4410
4455
|
};
|
|
4411
4456
|
},
|
|
4457
|
+
// 有意不处理 input.readOnlyDirectories:codex 的沙箱只限制写入,读不受限,
|
|
4458
|
+
// 附件目录本来就能读,无需放行。
|
|
4412
4459
|
startSession: async (input, signal) => {
|
|
4413
4460
|
if (disposed) throw new Error("instance disposed");
|
|
4414
4461
|
if (signal?.aborted) throw new Error("aborted");
|
package/locales/en.json
CHANGED
|
@@ -19,5 +19,26 @@
|
|
|
19
19
|
"title": "Launch arguments",
|
|
20
20
|
"description": "Additional CLI arguments passed to codex app-server on session start."
|
|
21
21
|
}
|
|
22
|
+
},
|
|
23
|
+
"account": {
|
|
24
|
+
"method": "Account connection",
|
|
25
|
+
"existing": "Use existing Codex configuration",
|
|
26
|
+
"chatgpt": "ChatGPT sign-in",
|
|
27
|
+
"apiKey": "API URL and key",
|
|
28
|
+
"url": "API base URL",
|
|
29
|
+
"key": "API key",
|
|
30
|
+
"keyStoredPlaceholder": "Stored secret — enter a new value to replace it",
|
|
31
|
+
"apiRequired": "Enter an HTTP or HTTPS API URL and an API key.",
|
|
32
|
+
"loginHint": "Use an account already on this machine, or sign in to another account.",
|
|
33
|
+
"detecting": "Checking accounts on this machine...",
|
|
34
|
+
"detectFailed": "Could not check accounts. Try again.",
|
|
35
|
+
"noAccounts": "No ChatGPT account was found on this machine.",
|
|
36
|
+
"addAnother": "Sign in to another ChatGPT account",
|
|
37
|
+
"useAccount": "Use {{email}}",
|
|
38
|
+
"alreadyAdded": "Already added",
|
|
39
|
+
"retry": "Check again",
|
|
40
|
+
"duplicate": "This ChatGPT account is already available as {{name}}.",
|
|
41
|
+
"directoryUnavailable": "Could not prepare a separate account on this machine. Check the connection and try again.",
|
|
42
|
+
"addAndSignIn": "Add and sign in"
|
|
22
43
|
}
|
|
23
44
|
}
|
package/locales/zh-CN.json
CHANGED
|
@@ -19,5 +19,26 @@
|
|
|
19
19
|
"title": "启动参数",
|
|
20
20
|
"description": "会话启动时传给 codex app-server 的额外命令行参数。"
|
|
21
21
|
}
|
|
22
|
+
},
|
|
23
|
+
"account": {
|
|
24
|
+
"method": "账户连接方式",
|
|
25
|
+
"existing": "使用现有 Codex 配置",
|
|
26
|
+
"chatgpt": "ChatGPT 登录",
|
|
27
|
+
"apiKey": "API URL 和密钥",
|
|
28
|
+
"url": "API 基础 URL",
|
|
29
|
+
"key": "API 密钥",
|
|
30
|
+
"keyStoredPlaceholder": "已存储的密钥 — 输入新值以替换",
|
|
31
|
+
"apiRequired": "请输入 HTTP 或 HTTPS API URL 和 API 密钥。",
|
|
32
|
+
"loginHint": "使用这台机器上已有的账户,或登录其他账户。",
|
|
33
|
+
"detecting": "正在检查这台机器上的账户...",
|
|
34
|
+
"detectFailed": "无法检查账户。请重试。",
|
|
35
|
+
"noAccounts": "在这台机器上未找到 ChatGPT 账户。",
|
|
36
|
+
"addAnother": "登录其他 ChatGPT 账户",
|
|
37
|
+
"useAccount": "使用 {{email}}",
|
|
38
|
+
"alreadyAdded": "已添加",
|
|
39
|
+
"retry": "再次检查",
|
|
40
|
+
"duplicate": "此 ChatGPT 账户已作为 {{name}} 可用。",
|
|
41
|
+
"directoryUnavailable": "无法在这台机器上为单独的账户做好准备。请检查连接后重试。",
|
|
42
|
+
"addAndSignIn": "添加并登录"
|
|
22
43
|
}
|
|
23
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-codex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2510",
|
|
4
4
|
"description": "Codex executor: Codex CLI over the app-server JSON-RPC protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -18,11 +18,19 @@
|
|
|
18
18
|
"access": "public"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
+
"@tailwindcss/node": "^4.3.0",
|
|
22
|
+
"@tailwindcss/oxide": "^4.3.0",
|
|
21
23
|
"@types/node": "24.12.4",
|
|
24
|
+
"@types/react": "~19.2.14",
|
|
25
|
+
"@types/react-dom": "^19.2.3",
|
|
22
26
|
"esbuild": "0.28.1",
|
|
27
|
+
"react": "19.2.6",
|
|
28
|
+
"react-dom": "19.2.6",
|
|
29
|
+
"tailwindcss": "^4.0.0",
|
|
30
|
+
"typescript": "~6.0.3",
|
|
23
31
|
"vite-plus": "0.2.2",
|
|
24
|
-
"
|
|
25
|
-
"ycodium-
|
|
32
|
+
"ycodium-executor-testing": "0.0.0",
|
|
33
|
+
"@ycodium-ai/plugin-api": "0.2.2510"
|
|
26
34
|
},
|
|
27
35
|
"ycodium": {
|
|
28
36
|
"plugin": "./dist/index.js",
|
|
@@ -33,11 +41,31 @@
|
|
|
33
41
|
{
|
|
34
42
|
"kind": "executor"
|
|
35
43
|
}
|
|
36
|
-
]
|
|
44
|
+
],
|
|
45
|
+
"ui": {
|
|
46
|
+
"assets": "./assets",
|
|
47
|
+
"entry": "ui.js",
|
|
48
|
+
"providerSettings": [
|
|
49
|
+
{
|
|
50
|
+
"id": "account",
|
|
51
|
+
"driverKind": "codex",
|
|
52
|
+
"ownedFields": {
|
|
53
|
+
"add": [
|
|
54
|
+
"homePath",
|
|
55
|
+
"shadowHomePath"
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
"ownedEnvironment": [
|
|
59
|
+
"YCODIUM_CODEX_API_KEY"
|
|
60
|
+
],
|
|
61
|
+
"genericFields": "collapsed"
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
37
65
|
},
|
|
38
66
|
"scripts": {
|
|
39
67
|
"build": "node build.mjs",
|
|
40
|
-
"typecheck": "tsgo --noEmit",
|
|
68
|
+
"typecheck": "tsgo --noEmit && tsgo --noEmit -p tsconfig.ui.json",
|
|
41
69
|
"test": "vp test run"
|
|
42
70
|
}
|
|
43
71
|
}
|