@wular/coder 0.2.12 → 0.3.1
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 +46 -19
- package/dist/app-server-Dwd7IcQH.js +3 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +55 -159
- package/dist/flow/index.d.ts +31 -0
- package/dist/flow/index.js +1 -0
- package/dist/index-CUy_WPvw.d.ts +611 -0
- package/dist/lib/broker.d.ts +1 -0
- package/dist/lib/broker.js +3 -16
- package/dist/runtime-DRtQOCSz.js +16 -0
- package/dist/sdk.d.ts +734 -0
- package/dist/sdk.js +1 -0
- package/dist/upgrade-DFAtgbtD.js +27 -0
- package/docs/config.md +67 -0
- package/docs/flows.md +239 -0
- package/docs/{custom-models.md → models.md} +28 -4
- package/docs/sdk.md +82 -0
- package/package.json +18 -5
- package/plugins/agents/skills/coder/SKILL.md +28 -15
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/skills/{handle → dispatch}/SKILL.md +27 -21
- package/plugins/cursor/.cursor-plugin/plugin.json +1 -1
- package/plugins/cursor/README.md +1 -1
- package/plugins/cursor/skills/coder/SKILL.md +27 -15
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
- **Fast dispatch.** Handoffs are instant, and light enough to spin up a large number of subagents at once.
|
|
15
15
|
- **Steerable tasks.** Full visibility into every task, from live progress to mid-run course corrections.
|
|
16
16
|
- **Unified permissions.** Three modes across all engines: _Read-only_, _Workspace-write_, and _Auto_.
|
|
17
|
+
- **Flows and SDK.** Orchestrate whole waves of tasks from a plain TypeScript file, or drive everything from your own code.
|
|
17
18
|
|
|
18
19
|
## Get started
|
|
19
20
|
|
|
@@ -50,7 +51,7 @@ npm install -g @openai/codex && codex login
|
|
|
50
51
|
npm install -g @anthropic-ai/claude-code && claude auth login
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
Or a local/provider model of your own (see [
|
|
54
|
+
Or a local/provider model of your own (see [Models](docs/models.md)). `coder setup-host` checks what's ready.
|
|
54
55
|
|
|
55
56
|
**3. Ask your host to use it:**
|
|
56
57
|
|
|
@@ -62,24 +63,6 @@ Or make it the default in AGENTS.md/CLAUDE.md:
|
|
|
62
63
|
|
|
63
64
|
Recommended setup: Claude Code as host (fable low/medium) and Codex (terra) as engine - best for performance and cost distribution.
|
|
64
65
|
|
|
65
|
-
## Configuration
|
|
66
|
-
|
|
67
|
-
Machine defaults live in `~/.coder/config.json`; a `coder.config.json` in a repo overrides per project.
|
|
68
|
-
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"chain": ["codex", "claude", "custom"],
|
|
72
|
-
"agents": {
|
|
73
|
-
"codex": { "model": "terra", "effort": "high", "permissions": "auto" },
|
|
74
|
-
"claude": { "model": "opus", "effort": "medium", "permissions": "auto" },
|
|
75
|
-
"custom": { "model": "qwen" }
|
|
76
|
-
},
|
|
77
|
-
"models": {
|
|
78
|
-
"qwen": { "baseUrl": "http://localhost:11434/v1", "model": "qwen2.5-coder:32b" }
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
66
|
## Staying up to date
|
|
84
67
|
|
|
85
68
|
```bash
|
|
@@ -88,6 +71,40 @@ coder upgrade
|
|
|
88
71
|
|
|
89
72
|
Updates the CLI through whichever package manager installed it and refreshes the host plugins to match. See `coder upgrade --help` for narrowing flags. Set `CODER_NO_UPDATE_CHECK=1` to silence the update notice.
|
|
90
73
|
|
|
74
|
+
## Flows
|
|
75
|
+
|
|
76
|
+
For well-defined workflows, ask your host to write a flow. A Coder flow is a TypeScript file that fans out coders at scale with built-in support for deterministic verification gates, crash/resume handling, etc. Ask like:
|
|
77
|
+
|
|
78
|
+
> Create a Coder flow that fixes every failing test file: one task per file, gated on its tests passing.
|
|
79
|
+
|
|
80
|
+
The harness authors the flow, you can review or tweak it, and it runs with live status and mid-run steering like any coder task. A generated flow looks like this:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// .coder/flows/first.ts
|
|
84
|
+
import { z } from 'zod';
|
|
85
|
+
import { task, gate, pipeline } from '@wular/coder/flow';
|
|
86
|
+
|
|
87
|
+
const failing = await task(
|
|
88
|
+
'Run `bun test` and list the failing test files.',
|
|
89
|
+
{
|
|
90
|
+
name: 'Find failing tests',
|
|
91
|
+
returns: z.object({ files: z.array(z.string()) }),
|
|
92
|
+
},
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
export default await pipeline(
|
|
96
|
+
failing.data.files,
|
|
97
|
+
file => task(`Fix the failing tests in ${file}.`, { name: file }),
|
|
98
|
+
(r, file) => gate(`bun test ${file}`),
|
|
99
|
+
);
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
See [Flows](docs/flows.md), or the [SDK](docs/sdk.md) to drive everything from your own code.
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
Machine defaults live in `~/.coder/config.json`; a `coder.config.json` in a repo overrides per project. See [Configuration](docs/config.md).
|
|
107
|
+
|
|
91
108
|
## Advanced usage
|
|
92
109
|
|
|
93
110
|
You rarely need these - the host agent drives tasks itself - but everything is scriptable:
|
|
@@ -100,6 +117,16 @@ coder task steer <task-id> "<text>" # continue a task with new instructions
|
|
|
100
117
|
coder task stop <task-id> # interrupt it
|
|
101
118
|
coder task stream [task-id] # watch the live progress log
|
|
102
119
|
coder task approve <task-id> <appr-id> # answer an escalated permission (--deny)
|
|
120
|
+
|
|
121
|
+
coder flow run <name|path> --wait # run a flow (--dry-run to preview prompts)
|
|
122
|
+
coder flow list # recent flow runs
|
|
123
|
+
coder flow discover # flows runnable here (workspace + global)
|
|
124
|
+
coder flow result [run-id] # progress and result across the whole wave
|
|
125
|
+
coder flow stream [run-id] # watch the wave live (replay + follow)
|
|
126
|
+
coder flow stop [run-id] # stop a run and its tasks
|
|
127
|
+
coder flow resume [run-id] # continue a crashed or edited run
|
|
128
|
+
|
|
129
|
+
coder docs [topic] # print bundled docs (flows, sdk, config, models)
|
|
103
130
|
```
|
|
104
131
|
|
|
105
132
|
Any `[task-id]` defaults to the most recent task.
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import e from"node:process";import t from"node:fs";import n from"node:path";import{execFileSync as r,spawn as i,spawnSync as a}from"node:child_process";import o from"node:os";import{fileURLToPath as s}from"node:url";import*as c from"zod/mini";import l from"node:net";import u from"node:readline";function d(e){try{let t=i(`codex`,[`archive`,e],{detached:!0,stdio:`ignore`});t.on(`error`,()=>{}),t.unref()}catch{}}function f(e){let r=n.join(process.env.CODEX_HOME||n.join(o.homedir(),`.codex`),`archived_sessions`);try{return t.readdirSync(r).some(t=>t.endsWith(`-${e}.jsonl`))}catch{return!1}}function p(e){return new Promise(t=>{try{let n=i(`codex`,[`unarchive`,e],{stdio:`ignore`});n.on(`error`,()=>t(!1)),n.on(`close`,e=>t(e===0))}catch{t(!1)}})}function ee(e){return a(`codex`,[`delete`,`--force`,e],{encoding:`utf8`}).status===0}const m=[`completed`,`failed`,`cancelled`],te=[`queued`,`running`],ne=/^[a-z0-9][a-z0-9_-]*$/i;function h(e){return ne.test(e)}function g(e,t){if(!h(e))throw Error(`Invalid ${t} "${e}".`)}function _(){return n.resolve(process.env.CODER_HOME||n.join(o.homedir(),`.coder`))}const v=new Map;function re(e){let t=v.get(e);if(t!==void 0)return t;let n;try{n=r(`git`,[`rev-parse`,`--show-toplevel`],{cwd:e,encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`]}).trim()}catch{n=e}return v.set(e,n),n}const y=`global`;function b(e){return n.join(_(),`state`,y)}let x=null;function S(){if(x)return x;let e=n.join(_(),`state`),r=[];try{r=t.readdirSync(e,{withFileTypes:!0})}catch{}return x=r.filter(e=>e.isDirectory()&&e.name!==y).map(t=>n.join(e,t.name)),x}function C(e){return n.join(b(e),`jobs`)}const ie=10*6e4;function w(e){return n.join(b(e),`archive`)}function T(e,r){g(r,`task id`);let i=n.join(C(e),r);if(t.existsSync(n.join(i,`job.json`)))return i;let a=n.join(w(e),r);if(t.existsSync(n.join(a,`job.json`)))return a;for(let e of S()){let i=n.join(e,`jobs`,r);if(t.existsSync(n.join(i,`job.json`)))return i}return i}function E(e,t){return t.archived?t:O(e,t.id,{archived:!0,archivedAt:new Date().toISOString()})}function D(e,r){let i=E(e,r);r.engine===`codex`&&r.threadId&&d(r.threadId);let a=T(e,r.id),o=n.join(w(e),r.id);if(a!==o)try{t.mkdirSync(w(e),{recursive:!0}),t.renameSync(a,o)}catch{}return i}function ae(){let e=Math.random().toString(36).slice(2,8);return`task-${Date.now().toString(36)}-${e}`}function O(e,r,i){let a=T(e,r);t.mkdirSync(a,{recursive:!0});let o=n.join(a,`job.json`),s={...A(e,r)??{id:r,createdAt:new Date().toISOString(),status:`queued`},...i,updatedAt:new Date().toISOString()};return t.writeFileSync(o,`${JSON.stringify(s,null,2)}\n`,`utf8`),s}function k(e){return!e.engine&&(e.agent===`codex`||e.agent===`claude`)&&(e.engine=e.agent),e}function A(e,r){if(!h(r))return null;let i=n.join(T(e,r),`job.json`);if(!t.existsSync(i))return null;try{return k(JSON.parse(t.readFileSync(i,`utf8`)))}catch{return null}}function oe(e,n){let r=T(e,n);return t.existsSync(r)?(t.rmSync(r,{recursive:!0,force:!0}),!0):!1}function se(e){if(!e)return!1;try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}const j=new Map;function M(e){let t=j.get(e);if(t&&Date.now()-t.at<5e3)return t.value;let n=ce(e);return j.set(e,{at:Date.now(),value:n}),n}function ce(e){try{let t=r(`ps`,[`-o`,`lstart=`,`-p`,String(e)],{encoding:`utf8`,stdio:[`ignore`,`pipe`,`ignore`],env:{...process.env,TZ:Intl.DateTimeFormat().resolvedOptions().timeZone}}).trim(),n=t?Date.parse(t):NaN;return Number.isFinite(n)?n:null}catch{return null}}function le(e,t){if(!se(e))return!1;let n=M(e),r=Date.parse(t.createdAt??``);return n===null||!Number.isFinite(r)||n<=r+6e4}function N(e,t){if(t.status!==`running`&&t.status!==`queued`)return t;let n;if(t.pid)n=!le(t.pid,t);else{let e=Date.parse(t.updatedAt??t.createdAt??``);n=Number.isFinite(e)&&Date.now()-e>6e4}return n?O(e,t.id,{status:`failed`,error:`worker exited without finishing`,completedAt:new Date().toISOString()}):t}function P(e,r){let i=[];for(let a of e){let e=[];try{e=t.readdirSync(a)}catch{continue}for(let o of e){if(r.has(o))continue;let e=n.join(a,o,`job.json`);try{let n=k(JSON.parse(t.readFileSync(e,`utf8`)));r.add(o),i.push(n)}catch{}}}return i}const F=(e,t)=>String(t.updatedAt??``).localeCompare(String(e.updatedAt??``));function ue(e){let t=[C(e),...S().map(e=>n.join(e,`jobs`))],r=[];for(let n of P(t,new Set))n.archived?D(e,n):r.push(N(e,n));return r.sort(F)}function I(e,t){let r=t?.migrate??!0,i=new Set,a=P([w(e)],i),o=[C(e),...S().map(e=>n.join(e,`jobs`))];for(let t of P(o,i))t.archived&&a.push(r?D(e,t):t);return a.sort(F)}function de(e,t){let n=[...ue(e),...I(e)].sort(F);if(!t)return n[0]??null;let r=n.find(e=>e.id===t);if(r)return r;let i=n.filter(e=>e.id.startsWith(t));if(i.length===1)return i[0];if(i.length>1)throw Error(`Job reference "${t}" is ambiguous. Use a longer id.`);return null}function fe(e,r){let i=T(e,r);try{t.mkdirSync(i,{recursive:!0}),t.writeFileSync(n.join(i,`heartbeat`),``,`utf8`)}catch{}}function pe(e,r){let i=T(e,r.id),a=Date.parse(r.updatedAt??``)||0;for(let e of[`log.jsonl`,`heartbeat`])try{a=Math.max(a,t.statSync(n.join(i,e)).mtimeMs)}catch{}return a?new Date(a).toISOString():void 0}async function me(e,t,n=400){let r=t;for(;!m.includes(r.status);)await new Promise(e=>setTimeout(e,n)),r=N(e,A(e,r.id)??r);return r}const L=`steer-queue.jsonl`;function he(e,r,i){let a=T(e,r);t.mkdirSync(a,{recursive:!0}),t.appendFileSync(n.join(a,L),`${JSON.stringify({at:new Date().toISOString(),text:i})}\n`,`utf8`)}function ge(e,r){let i=T(e,r),a=n.join(i,L),o=n.join(i,`steer-claim-${process.pid}-${Date.now()}.tmp`);try{t.renameSync(a,o)}catch{return[]}try{return t.readFileSync(o,`utf8`).split(/\r?\n/).filter(Boolean).map(e=>{try{return String(JSON.parse(e).text??``)}catch{return``}}).filter(Boolean)}finally{try{t.unlinkSync(o)}catch{}}}function _e(e,r,i){let a=T(e,r);t.mkdirSync(a,{recursive:!0}),t.appendFileSync(n.join(a,`log.jsonl`),`${JSON.stringify({at:new Date().toISOString(),...i})}\n`,`utf8`)}function ve(e,r,i=40){let a=n.join(T(e,r),`log.jsonl`);return t.existsSync(a)?t.readFileSync(a,`utf8`).split(/\r?\n/).filter(Boolean).slice(-i).map(e=>{try{return JSON.parse(e)}catch{return{message:e}}}):[]}function ye(){let e=n.dirname(s(import.meta.url));for(let r=0;r<10;r++){let r=n.join(e,`package.json`);try{if(JSON.parse(t.readFileSync(r,`utf8`)).name===`@wular/coder`)return e}catch{}let i=n.dirname(e);if(i===e)break;e=i}return n.resolve(n.dirname(s(import.meta.url)),`..`)}const R=ye(),be=t.existsSync(n.join(R,`dist/cli.js`))?n.join(R,`dist/cli.js`):n.join(R,`src/cli.ts`);function z(){try{return JSON.parse(t.readFileSync(n.join(R,`package.json`),`utf8`)).version??`unknown`}catch{return`unknown`}}function xe(e){try{return JSON.parse(t.readFileSync(e,`utf8`)).version??null}catch{return null}}function Se(){return R}const B=c.optional(c.boolean()),V=c.optional(c.string()),Ce={cwd:V,json:B},we=c.optional(c.union([c.literal(`all`),c.coerce.number().check(c.int(),c.positive())],{error:`expected a positive integer or "all"`})),Te=c.optional(c.union([c.literal(`all`),c.coerce.number().check(c.int(),c.nonnegative())],{error:`expected a number or "all"`}));function H(e){let t=e.def;for(;t;){if(t.type===`boolean`)return!0;let e=t.innerType??t.in;t=e?e.def:void 0}return!1}function Ee(e,t){let n=t.shape,r={},i=[],a=!1,o=(e,t,i,a)=>{let o=n[t],s=a?`-`:`--`;if(!o)throw Error(`Unknown option ${s}${e} (use -- to pass literal text starting with -)`);if(H(o))return r[t]=i===void 0||i!==`false`,0;if(i===void 0)throw Error(`Missing value for ${s}${e}`);return r[t]=i,1};for(let t=0;t<e.length;t+=1){let r=e[t];if(a){i.push(r);continue}if(r===`--`){a=!0;continue}if(!r.startsWith(`-`)||r===`-`){i.push(r);continue}if(r.startsWith(`--`)){let[i,a]=r.slice(2).split(`=`,2);a===void 0&&n[i]&&!H(n[i])?t+=o(i,i,e[t+1],!1):o(i,i,a,!1);continue}let s=r.slice(1);n[s]&&!H(n[s])?t+=o(s,s,e[t+1],!0):o(s,s,void 0,!0)}let s=t.safeParse(r);if(!s.success){let e=s.error.issues[0],t=String(e.path[0]??``),n=r[t];throw Error(n===void 0?`Missing required --${t}.`:`Invalid --${t} value ${JSON.stringify(n)}: ${e.message}`)}return{options:s.data,positionals:i}}function De(e){return String(e??``).replace(/[^A-Za-z0-9._-]/g,`-`).replace(/^-+|-+$/g,``)}function Oe(t,r=e.platform){return r===`win32`?`pipe:\\\\.\\pipe\\${De(`${n.win32.basename(t)}-codex-app-server`)}`:`unix:${n.join(t,`broker.sock`)}`}function U(e){if(typeof e!=`string`||e.length===0)throw Error(`Missing broker endpoint.`);if(e.startsWith(`pipe:`)){let t=e.slice(5);if(!t)throw Error(`Broker pipe endpoint is missing its path.`);return{kind:`pipe`,path:t}}if(e.startsWith(`unix:`)){let t=e.slice(5);if(!t)throw Error(`Broker Unix socket endpoint is missing its path.`);return{kind:`unix`,path:t}}throw Error(`Unsupported broker endpoint: ${e}`)}function ke(e=`coder-`){return t.mkdtempSync(n.join(o.tmpdir(),e))}function Ae(e){let t=U(e);return l.createConnection({path:t.path})}async function W(e,t=2e3){let n=Date.now();for(;Date.now()-n<t;){if(await new Promise(t=>{let n=Ae(e);n.on(`connect`,()=>{n.end(),t(!0)}),n.on(`error`,()=>t(!1))}))return!0;await new Promise(e=>setTimeout(e,50))}return!1}function je({scriptPath:n,cwd:r,endpoint:a,pidFile:o,logFile:s,env:c=e.env}){let l=t.openSync(s,`a`),u=i(e.execPath,[n,`serve`,`--endpoint`,a,`--cwd`,r,`--pid-file`,o],{cwd:r,env:c,detached:!0,stdio:[`ignore`,l,l]});return u.unref(),t.closeSync(l),u}function Me(){let e=[new URL(`./lib/broker.js`,import.meta.url),new URL(`./broker.js`,import.meta.url)];for(let n of e){let e=s(n);if(t.existsSync(e))return e}throw Error("Coder broker script not found next to the runtime. Rebuild with `bun run build`.")}function G(e){return n.join(b(e),`broker.json`)}function K(e){let n=G(e);if(!t.existsSync(n))return null;try{return JSON.parse(t.readFileSync(n,`utf8`))}catch{return null}}function Ne(e,n){let r=b(e);t.mkdirSync(r,{recursive:!0}),t.writeFileSync(G(e),`${JSON.stringify(n,null,2)}\n`,`utf8`)}function Pe(e){let n=G(e);t.existsSync(n)&&t.unlinkSync(n)}async function Fe(e){if(!e)return!1;try{return await W(e,150)}catch{return!1}}async function Ie(t,r={}){let i=r.scriptPath??Me(),a=z(),o=K(t),s=o?.version===a&&o?.scriptPath===i;if(o&&s&&await Fe(o.endpoint))return o;o&&(q({endpoint:o.endpoint??null,pidFile:o.pidFile??null,logFile:o.logFile??null,sessionDir:o.sessionDir??null,pid:o.pid??null,killProcess:r.killProcess??null}),Pe(t));let c=ke(),l=(r.createBrokerEndpoint??Oe)(c,r.platform),u=n.join(c,`broker.pid`),d=n.join(c,`broker.log`),f=je({scriptPath:i,cwd:t,endpoint:l,pidFile:u,logFile:d,env:r.env??e.env});if(!await W(l,r.timeoutMs??2e3))return q({endpoint:l,pidFile:u,logFile:d,sessionDir:c,pid:f.pid??null,killProcess:r.killProcess??null}),null;let p={endpoint:l,pidFile:u,logFile:d,sessionDir:c,pid:f.pid??null,version:a,scriptPath:i};return Ne(t,p),p}function q({endpoint:e=null,pidFile:r,logFile:i,sessionDir:a=null,pid:o=null,killProcess:s=null}){if(Number.isFinite(o)&&s)try{s(o)}catch{}if(r&&t.existsSync(r)&&t.unlinkSync(r),i&&t.existsSync(i)&&t.unlinkSync(i),e)try{let n=U(e);n.kind===`unix`&&t.existsSync(n.path)&&t.unlinkSync(n.path)}catch{}let c=a??(r?n.dirname(r):i?n.dirname(i):null);if(c&&t.existsSync(c))try{t.rmdirSync(c)}catch{}}function J(t,n=[],r={}){let i=a(t,n,{cwd:r.cwd,env:r.env,encoding:`utf8`,input:r.input,maxBuffer:r.maxBuffer,stdio:r.stdio??`pipe`,shell:e.platform===`win32`?e.env.SHELL||!0:!1,windowsHide:!0});return{command:t,args:n,status:i.status??0,signal:i.signal??null,stdout:i.stdout??``,stderr:i.stderr??``,error:i.error??null}}function Le(e,t=[`--version`],n={}){let r=J(e,t,n);return r.error&&r.error.code===`ENOENT`?{available:!1,detail:`not found`}:r.error?{available:!1,detail:r.error.message}:r.status===0?{available:!0,detail:r.stdout.trim()||r.stderr.trim()||`ok`}:{available:!1,detail:r.stderr.trim()||r.stdout.trim()||`exit ${r.status}`}}function Re(e){return/not found|no running instance|cannot find|does not exist|no such process/i.test(e)}function ze(t,n={}){if(!Number.isFinite(t))return{attempted:!1,delivered:!1,method:null};let r=t,i=n.platform??e.platform,a=n.runCommandImpl??J,o=n.killImpl??e.kill.bind(e);if(i===`win32`){let e=a(`taskkill`,[`/PID`,String(r),`/T`,`/F`],{cwd:n.cwd,env:n.env});if(!e.error&&e.status===0)return{attempted:!0,delivered:!0,method:`taskkill`,result:e};let t=`${e.stderr}\n${e.stdout}`.trim();if(!e.error&&Re(t))return{attempted:!0,delivered:!1,method:`taskkill`,result:e};if(e.error?.code===`ENOENT`)try{return o(r),{attempted:!0,delivered:!0,method:`kill`}}catch(e){if(e?.code===`ESRCH`)return{attempted:!0,delivered:!1,method:`kill`};throw e}throw e.error?e.error:Error(Be(e))}try{return o(-r,`SIGTERM`),{attempted:!0,delivered:!0,method:`process-group`}}catch(e){if(e?.code!==`ESRCH`)try{return o(r,`SIGTERM`),{attempted:!0,delivered:!0,method:`process`}}catch(e){if(e?.code===`ESRCH`)return{attempted:!0,delivered:!1,method:`process`};throw e}return{attempted:!0,delivered:!1,method:`process-group`}}}function Be(e){let t=[`${e.command} ${e.args.join(` `)}`.trim()];e.signal?t.push(`signal=${e.signal}`):t.push(`exit=${e.status}`);let n=(e.stderr||``).trim(),r=(e.stdout||``).trim();return n?t.push(n):r&&t.push(r),t.join(`: `)}const Ve=`CODER_APP_SERVER_ENDPOINT`,He=-32001;let Y;function Ue(){if(Y===void 0){let e=J(`codex`,[`--version`]),t=/(\d+\.\d+\.\d+(?:-[\w.]+)?)/.exec(`${e.stdout} ${e.stderr}`);Y=t?t[1]:`0.144.1`}return Y}function X(){return{title:`Coder`,name:`coder`,version:Ue()}}const Z={experimentalApi:!1,requestAttestation:!1,optOutNotificationMethods:[`item/agentMessage/delta`,`item/reasoning/summaryTextDelta`,`item/reasoning/summaryPartAdded`,`item/reasoning/textDelta`]};function Q(e,t,n){return n===void 0?{code:e,message:t}:{code:e,message:t,data:n}}function $(e,t){let n=Error(e);return n.data=t,t?.code!==void 0&&(n.rpcCode=t.code),n}var We=class{cwd;options;pending;nextId;stderr;closed;exitError;notificationHandler;serverRequestHandler;lineBuffer;transport;exitPromise;exitResolved;resolveExit;handleServerRequest;constructor(e,t={}){this.cwd=e,this.options=t,this.pending=new Map,this.nextId=1,this.stderr=``,this.closed=!1,this.exitError=null,this.notificationHandler=null,this.serverRequestHandler=null,this.lineBuffer=``,this.transport=`unknown`,this.handleServerRequest=e=>this.defaultHandleServerRequest(e),this.exitPromise=new Promise(e=>{this.resolveExit=e})}setNotificationHandler(e){this.notificationHandler=e}setServerRequestHandler(e){this.serverRequestHandler=e}request(e,t){if(this.closed)throw Error(`codex app-server client is closed.`);let n=this.nextId;return this.nextId+=1,new Promise((r,i)=>{this.pending.set(n,{resolve:r,reject:i,method:e}),this.sendMessage({id:n,method:e,params:t})})}notify(e,t={}){this.closed||this.sendMessage({method:e,params:t})}handleChunk(e){this.lineBuffer+=e;let t=this.lineBuffer.indexOf(`
|
|
2
|
+
`);for(;t!==-1;){let e=this.lineBuffer.slice(0,t);this.lineBuffer=this.lineBuffer.slice(t+1),this.handleLine(e),t=this.lineBuffer.indexOf(`
|
|
3
|
+
`)}}handleLine(e){if(!e.trim())return;let t;try{t=JSON.parse(e)}catch(t){this.handleExit($(`Failed to parse codex app-server JSONL: ${t instanceof Error?t.message:String(t)}`,{line:e}));return}if(t.id!==void 0&&t.method){this.handleServerRequest(t);return}if(t.id!==void 0){let e=this.pending.get(t.id);if(!e)return;this.pending.delete(t.id),t.error?e.reject($(t.error.message??`codex app-server ${e.method} failed.`,t.error)):e.resolve(t.result??{});return}t.method&&this.notificationHandler&&this.notificationHandler(t)}defaultHandleServerRequest(e){let t=this.serverRequestHandler;if(!t){this.sendMessage({id:e.id,error:Q(-32601,`Unsupported server request: ${e.method}`)});return}Promise.resolve().then(()=>t(e.method,e.params??{})).then(t=>{this.sendMessage({id:e.id,result:t??{}})}).catch(t=>{this.sendMessage({id:e.id,error:Q(-32e3,t instanceof Error?t.message:String(t))})})}handleExit(e){if(!this.exitResolved){this.exitResolved=!0,this.exitError=e??null;for(let e of this.pending.values())e.reject(this.exitError??Error(`codex app-server connection closed.`));this.pending.clear(),this.resolveExit(void 0)}}sendMessage(e){throw Error(`sendMessage must be implemented by subclasses.`)}},Ge=class extends We{proc;readline;constructor(e,t={}){super(e,t),this.transport=`direct`}async initialize(){this.proc=i(`codex`,[`-c`,`sandbox_workspace_write.network_access=false`,`app-server`,`--disable`,`plugins`],{cwd:this.cwd,env:this.options.env??e.env,stdio:[`pipe`,`pipe`,`pipe`],shell:e.platform===`win32`?e.env.SHELL||!0:!1,windowsHide:!0});let t=this.proc.stdout,n=this.proc.stderr;if(!t||!n)throw Error(`codex app-server did not expose stdio streams.`);t.setEncoding(`utf8`),n.setEncoding(`utf8`),n.on(`data`,e=>{this.stderr+=e}),this.proc.on(`error`,e=>{this.handleExit(e)}),this.proc.on(`exit`,(e,t)=>{let n=this.stderr.trim(),r=e===0?null:$(`codex app-server exited unexpectedly (${t?`signal ${t}`:`exit ${e}`}).${n?`\n${n}`:``}`);this.handleExit(r)}),this.readline=u.createInterface({input:t}),this.readline.on(`line`,e=>{this.handleLine(e)}),await this.request(`initialize`,{clientInfo:this.options.clientInfo??X(),capabilities:this.options.capabilities??Z}),this.notify(`initialized`,{})}async close(){if(this.closed){await this.exitPromise;return}this.closed=!0,this.readline&&this.readline.close(),this.proc&&!this.proc.killed&&(this.proc.stdin?.end(),setTimeout(()=>{if(this.proc&&!this.proc.killed&&this.proc.exitCode===null)if(e.platform===`win32`)try{ze(this.proc.pid)}catch{}else this.proc.kill(`SIGTERM`)},50).unref?.()),await this.exitPromise}sendMessage(e){let t=`${JSON.stringify(e)}\n`,n=this.proc?.stdin;if(!n)throw Error(`codex app-server stdin is not available.`);n.write(t)}},Ke=class extends We{endpoint;socket;constructor(e,t={}){super(e,t),this.transport=`broker`,this.endpoint=t.brokerEndpoint}async initialize(){await new Promise((e,t)=>{let n=U(this.endpoint);this.socket=l.createConnection({path:n.path}),this.socket.setEncoding(`utf8`),this.socket.on(`connect`,e),this.socket.on(`data`,e=>{this.handleChunk(e)}),this.socket.on(`error`,e=>{this.exitResolved||t(e),this.handleExit(e)}),this.socket.on(`close`,()=>{this.handleExit(this.exitError)})}),await this.request(`initialize`,{clientInfo:this.options.clientInfo??X(),capabilities:this.options.capabilities??Z}),this.notify(`initialized`,{})}async close(){if(this.closed){await this.exitPromise;return}this.closed=!0,this.socket&&this.socket.end(),await this.exitPromise}sendMessage(e){let t=`${JSON.stringify(e)}\n`,n=this.socket;if(!n)throw Error(`codex app-server broker connection is not connected.`);n.write(t)}},qe=class{static async connect(t,n={}){let r=null;n.disableBroker||(r=n.brokerEndpoint??n.env?.CODER_APP_SERVER_ENDPOINT??e.env.CODER_APP_SERVER_ENDPOINT??null,!r&&n.reuseExistingBroker&&(r=K(t)?.endpoint??null),!r&&!n.reuseExistingBroker&&(r=(await Ie(t,{env:n.env}))?.endpoint??null));let i=r?new Ke(t,{...n,brokerEndpoint:r}):new Ge(t,n);return await i.initialize(),i}};export{M as A,te as B,de as C,I as D,pe as E,T as F,ee as H,re as I,fe as L,ve as M,N,ue as O,_ as P,me as R,he as S,h as T,f as U,m as V,p as W,_e as _,U as a,ge as b,we as c,Te as d,be as f,ie as g,Se as h,Le as i,A as j,E as k,Ee as l,z as m,Ve as n,Ce as o,xe as p,qe as r,B as s,He as t,V as u,D as v,ae as w,oe as x,g as y,O as z};
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|