@gencode/server 0.3.10 → 0.3.12

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/CHANGELOG.md CHANGED
@@ -1,5 +1,20 @@
1
1
  # @gencode/server
2
2
 
3
+ ## 0.3.12
4
+
5
+ ### Patch Changes
6
+
7
+ - ac37ac3: `aimax-server` 的 `POST /run` 成功接收响应现在会返回 `receivedAt` 和 `respondedAt` 两个中国本地时间字段,格式与 CLI 日志一致(`YYYY-MM-DD HH:mm:ss.SSS`),方便上游记录 server 接收请求与返回 HTTP acceptance 的时间点。任务进度和最终结果仍继续通过 CLI stdout、callback 或 websocket 通道发送。
8
+
9
+ ## 0.3.11
10
+
11
+ ### Patch Changes
12
+
13
+ - 6a3da33: `aimax-server` 的 `POST /run` 请求现在明确按完整 `aimax run` 参数合同接收 `run` 字段,使用 camelCase JSON 字段名传递 CLI 选项。调用方可以通过 server 模式传入 `resumeRequestId`、`resumeInputJson`、`resumeFromFile` 等 HITL / UI Tool 恢复参数;这些字段会沿用既有 CLI run 路径执行,执行进度和结果仍通过已配置的 stdout、callback 或 websocket 输出。
14
+ - Updated dependencies [0334050]
15
+ - @gencode/agents@0.17.2
16
+ - @gencode/cli@0.15.2
17
+
3
18
  ## 0.3.10
4
19
 
5
20
  ### Patch Changes
package/README.md CHANGED
@@ -18,8 +18,32 @@ If the accepted `/run` request does not provide `run.pluginsConfig` and does not
18
18
  override `AIMAX_PLUGINS_CONFIG` in request `env`, the run inherits the startup
19
19
  plugins config path so the CLI execution uses the preloaded plugin registry.
20
20
 
21
- `POST /run` accepts normal `aimax run` options under `run`. For structured
22
- message input, pass `run.messages` instead of encoding JSON into `run.message`:
21
+ `POST /run` accepts the same run options as `aimax run` under `run`, using the
22
+ CLI `RunOptions` camelCase field names. For example, `--session-id` becomes
23
+ `sessionId`, `--resume-request-id` becomes `resumeRequestId`, and
24
+ `--resume-input-json` becomes `resumeInputJson`.
25
+
26
+ When a valid run is accepted, the server responds immediately with HTTP `202`.
27
+ The response only acknowledges that the one-shot run was accepted; task progress
28
+ and completion still use the configured CLI stdout, callback, or websocket
29
+ channels.
30
+
31
+ ```json
32
+ {
33
+ "status": "running",
34
+ "accepted": true,
35
+ "receivedAt": "2026-07-02 16:00:00.000",
36
+ "respondedAt": "2026-07-02 16:00:00.012"
37
+ }
38
+ ```
39
+
40
+ `receivedAt` is the server-side time when `/run` handling started.
41
+ `respondedAt` is the server-side time immediately before the HTTP acceptance
42
+ response is written. Both fields use the same China local timestamp format as
43
+ CLI logs: `YYYY-MM-DD HH:mm:ss.SSS`.
44
+
45
+ For structured message input, pass `run.messages` instead of encoding JSON into
46
+ `run.message`:
23
47
 
24
48
  ```json
25
49
  {
@@ -40,3 +64,16 @@ message input, pass `run.messages` instead of encoding JSON into `run.message`:
40
64
 
41
65
  `run.messages` uses the same structured Message format as `aimax run --from-file`.
42
66
  `run.message` remains plain user text and is not JSON-parsed by the server.
67
+
68
+ Resume-related run options are also forwarded through the same CLI path:
69
+
70
+ ```json
71
+ {
72
+ "run": {
73
+ "dataDir": "/data/user1",
74
+ "sessionId": "sess-001",
75
+ "resumeRequestId": "hitl-001",
76
+ "resumeInputJson": "{\"action\":\"submit\",\"values\":{\"approved\":true}}"
77
+ }
78
+ }
79
+ ```
package/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{t as e}from"./server-BWdQz0S2.js";function t(e){let t=!1;return()=>{t||(t=!0,n(e))}}async function n(e){let t=e.exit??(e=>process.exit(e)),n=e.onLog??(()=>void 0),a=e.graceMs??3e4,o=e.server.getStatus();if(!r(o)){await e.server.stop().catch(e=>{n(`server shutdown stop failed`,{error:String(e),status:o})}),t(0);return}n(`server shutdown signal received; waiting for active run`,{status:o,graceMs:a}),await e.server.stop().catch(e=>{n(`server shutdown stop failed`,{error:String(e),status:o})});let s=await i(e.server.done,a);if(s.timedOut){n(`server shutdown grace period elapsed before run finished`,{status:o,graceMs:a}),t(1);return}n(`server shutdown completed after active run finished`,{status:o,exitCode:s.exitCode}),t(s.exitCode)}function r(e){return e===`running`||e===`draining`}async function i(e,t){let n,r=new Promise(e=>{n=setTimeout(()=>e({timedOut:!0}),t),n.unref?.()});try{return await Promise.race([e.then(e=>({timedOut:!1,exitCode:e.exitCode})),r])}finally{n&&clearTimeout(n)}}function a(e){let t={};for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`--host`){t.host=e[++n];continue}if(r===`--port`){t.port=o(e[++n],`--port`);continue}if(r===`--plugins-config`){t.pluginsConfig=s(e[++n],`--plugins-config`);continue}if(r===`--request-timeout-ms`){t.requestTimeoutMs=c(e[++n],`--request-timeout-ms`);continue}if(r===`--shutdown-grace-ms`){t.shutdownGraceMs=c(e[++n],`--shutdown-grace-ms`);continue}throw(r===`--help`||r===`-h`)&&(l(),process.exit(0)),Error(`Unknown option: ${r}`)}return t}function o(e,t){let n=c(e,t);if(n>65535)throw Error(`Invalid ${t}: ${e}. Must be between 0 and 65535.`);return n}function s(e,t){if(e===void 0||e.trim()===``)throw Error(`Missing value for ${t}`);return e}function c(e,t){if(e===void 0||e.trim()===``)throw Error(`Missing value for ${t}`);let n=Number(e);if(!Number.isInteger(n)||n<0)throw Error(`Invalid ${t}: ${e}. Must be a non-negative integer.`);return n}function l(){process.stdout.write(`AIMax one-shot prestart server
2
+ import{t as e}from"./server-VB3yAKQp.js";function t(e){let t=!1;return()=>{t||(t=!0,n(e))}}async function n(e){let t=e.exit??(e=>process.exit(e)),n=e.onLog??(()=>void 0),a=e.graceMs??3e4,o=e.server.getStatus();if(!r(o)){await e.server.stop().catch(e=>{n(`server shutdown stop failed`,{error:String(e),status:o})}),t(0);return}n(`server shutdown signal received; waiting for active run`,{status:o,graceMs:a}),await e.server.stop().catch(e=>{n(`server shutdown stop failed`,{error:String(e),status:o})});let s=await i(e.server.done,a);if(s.timedOut){n(`server shutdown grace period elapsed before run finished`,{status:o,graceMs:a}),t(1);return}n(`server shutdown completed after active run finished`,{status:o,exitCode:s.exitCode}),t(s.exitCode)}function r(e){return e===`running`||e===`draining`}async function i(e,t){let n,r=new Promise(e=>{n=setTimeout(()=>e({timedOut:!0}),t),n.unref?.()});try{return await Promise.race([e.then(e=>({timedOut:!1,exitCode:e.exitCode})),r])}finally{n&&clearTimeout(n)}}function a(e){let t={};for(let n=0;n<e.length;n+=1){let r=e[n];if(r===`--host`){t.host=e[++n];continue}if(r===`--port`){t.port=o(e[++n],`--port`);continue}if(r===`--plugins-config`){t.pluginsConfig=s(e[++n],`--plugins-config`);continue}if(r===`--request-timeout-ms`){t.requestTimeoutMs=c(e[++n],`--request-timeout-ms`);continue}if(r===`--shutdown-grace-ms`){t.shutdownGraceMs=c(e[++n],`--shutdown-grace-ms`);continue}throw(r===`--help`||r===`-h`)&&(l(),process.exit(0)),Error(`Unknown option: ${r}`)}return t}function o(e,t){let n=c(e,t);if(n>65535)throw Error(`Invalid ${t}: ${e}. Must be between 0 and 65535.`);return n}function s(e,t){if(e===void 0||e.trim()===``)throw Error(`Missing value for ${t}`);return e}function c(e,t){if(e===void 0||e.trim()===``)throw Error(`Missing value for ${t}`);let n=Number(e);if(!Number.isInteger(n)||n<0)throw Error(`Invalid ${t}: ${e}. Must be a non-negative integer.`);return n}function l(){process.stdout.write(`AIMax one-shot prestart server
3
3
 
4
4
  Usage:
5
5
  aimax-server [--host 127.0.0.1] [--port 0] [--plugins-config /image/plugins.json] [--request-timeout-ms 60000] [--shutdown-grace-ms 30000]
package/dist/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
+ import { RunOptions } from "@gencode/cli";
2
+
1
3
  //#region src/server.d.ts
2
4
  type AimaxServerStatus = "starting" | "warming" | "ready" | "ready_degraded" | "running" | "draining" | "exiting";
3
5
  type ServerRunRequest = {
4
6
  env?: ServerRequestEnv;
5
7
  run: ServerRunOptions;
6
8
  };
7
- type ServerRunOptions = Record<string, unknown>;
9
+ type ServerRunOptions = RunOptions;
8
10
  type ServerRequestEnv = Record<string, string | number | boolean | null>;
9
11
  type SystemWarmState = {
10
12
  runtimeInitialized: true;
@@ -36,4 +38,4 @@ type AimaxServerHandle = {
36
38
  };
37
39
  declare function createAimaxServer(options?: AimaxServerOptions): AimaxServerHandle;
38
40
  //#endregion
39
- export { type AimaxServerHandle, type AimaxServerOptions, type AimaxServerStatus, type ServerRequestEnv, type ServerRunRequest, createAimaxServer };
41
+ export { type AimaxServerHandle, type AimaxServerOptions, type AimaxServerStatus, type ServerRequestEnv, type ServerRunOptions, type ServerRunRequest, createAimaxServer };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./server-BWdQz0S2.js";export{e as createAimaxServer};
1
+ import{t as e}from"./server-VB3yAKQp.js";export{e as createAimaxServer};
@@ -0,0 +1 @@
1
+ import e from"node:http";import t from"node:fs/promises";function n(t={}){let n=t.host??`127.0.0.1`,o=t.port??0,d=t.maxBodyBytes??1048576,m=t.executeRun??c,h=t.prepareSystemRuntime??l,g=t.onLog??(()=>void 0),_=t.pluginsConfig,v=`starting`,y,b,x=null,S=!1,C=()=>void 0,w=new Promise(e=>{C=e});function T(e){S||(S=!0,C(e))}function E(e){v=e,g(`server status changed`,{status:e})}async function D(){let e=x;x=null,!(!e||!e.listening)&&await new Promise((t,n)=>{e.close(e=>{e?n(e):t()})})}async function O(e,t){let n=r();if(v===`starting`||v===`warming`){p(t,503,{status:v,error:`server is not ready`});return}if(v!==`ready`&&v!==`ready_degraded`){p(t,409,{status:v,error:`server already accepted a run`});return}let i;try{i=a(await f(e,d))}catch(e){p(t,400,{status:v,error:e.message});return}E(`running`),D().catch(e=>{g(`failed to close listener after accepting run`,{error:String(e)})});let o=r();p(t,202,{status:v,accepted:!0,receivedAt:n,respondedAt:o}),k(i)}async function k(e){let t=0;try{let n=i(e.run,e.env,b);await s(e.env,()=>m(n)),typeof process.exitCode==`number`&&process.exitCode!==0&&(t=process.exitCode),E(`draining`)}catch(e){t=1,g(`run failed`,{error:String(e)}),E(`draining`)}finally{await D().catch(e=>{g(`failed to stop server during drain`,{error:String(e)})}),E(`exiting`),T({exitCode:t})}}async function A(e,t){let r=new URL(e.url??`/`,`http://${n}`);if(e.method===`GET`&&r.pathname===`/healthz`){p(t,200,{status:v});return}if(e.method===`GET`&&r.pathname===`/readyz`){let e=v===`ready`||v===`ready_degraded`;p(t,e?200:503,{status:v,ready:e,degraded:v===`ready_degraded`,warmupError:y});return}if(e.method===`POST`&&r.pathname===`/run`){await O(e,t);return}p(t,404,{status:v,error:`not found`})}async function j(){if(!x){E(`warming`),x=e.createServer((e,t)=>{A(e,t).catch(e=>{p(t,500,{status:v,error:String(e)})})}),await new Promise((e,t)=>{x.once(`error`,t),x.listen(o,n,()=>{x.off(`error`,t),e()})});try{let e=_?await u(_):void 0;e!==void 0&&(b=_),await h({pluginsConfig:e}),v===`warming`&&E(`ready`)}catch(e){y=String(e),g(`system warmup failed; continuing with cold run path`,{error:y}),v===`warming`&&E(`ready_degraded`)}t.requestTimeoutMs&&t.requestTimeoutMs>0&&setTimeout(()=>{(v===`ready`||v===`ready_degraded`)&&D().finally(()=>{E(`exiting`),T({exitCode:1})})},t.requestTimeoutMs).unref()}}function M(){if(!x?.listening)return``;let e=x.address();return`http://${e.address}:${e.port}`}return{start:j,stop:D,done:w,getStatus:()=>v,getUrl:M}}function r(e=new Date){let t=new Intl.DateTimeFormat(`en-CA`,{timeZone:`Asia/Shanghai`,year:`numeric`,month:`2-digit`,day:`2-digit`,hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1}),n=Object.fromEntries(t.formatToParts(e).map(e=>[e.type,e.value])),r=String(e.getMilliseconds()).padStart(3,`0`);return`${n.year}-${n.month}-${n.day} ${n.hour}:${n.minute}:${n.second}.${r}`}function i(e,t,n){return!n||Object.prototype.hasOwnProperty.call(e,`pluginsConfig`)||t&&Object.prototype.hasOwnProperty.call(t,`AIMAX_PLUGINS_CONFIG`)?e:{...e,pluginsConfig:n}}function a(e){if(!e||typeof e!=`object`)throw Error(`request body must be an object`);let t=e.env;t!==void 0&&o(t);let n=e.run;if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`request body must include run options`);return{env:t,run:n}}function o(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`request env must be an object when provided`);for(let[t,n]of Object.entries(e)){if(!t||t.includes(`=`))throw Error(`request env contains invalid key: ${t}`);if(n!==null&&typeof n!=`string`&&typeof n!=`number`&&typeof n!=`boolean`)throw Error(`request env value for ${t} must be string, number, boolean, or null`)}}async function s(e,t){if(!e||Object.keys(e).length===0)return t();let n=new Map;for(let[t,r]of Object.entries(e))n.set(t,process.env[t]),r===null?delete process.env[t]:process.env[t]=String(r);try{return await t()}finally{for(let[e,t]of n)t===void 0?delete process.env[e]:process.env[e]=t}}async function c(e){await(await d(`@gencode/cli`)).executeRun(e)}async function l(e={}){return(await d(`@gencode/agents/system-runtime`)).prepareSystemRuntime({config:e.pluginsConfig})}async function u(e){let n=await t.readFile(e,`utf-8`);return JSON.parse(n)}const d=Function(`specifier`,`return import(specifier)`);async function f(e,t){let n=[],r=0;for await(let i of e){let e=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=e.byteLength,r>t)throw Error(`request body is too large`);n.push(e)}let i=Buffer.concat(n).toString(`utf-8`);if(!i.trim())throw Error(`request body must not be empty`);try{return JSON.parse(i)}catch{throw Error(`request body must be valid JSON`)}}function p(e,t,n){e.headersSent||(e.writeHead(t,{"content-type":`application/json; charset=utf-8`}),e.end(`${JSON.stringify(n)}\n`))}export{n as t};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gencode/server",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "aimax-server": "./dist/bin.js"
@@ -19,8 +19,8 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "@gencode/agents": "0.17.1",
23
- "@gencode/cli": "0.15.1"
22
+ "@gencode/cli": "0.15.2",
23
+ "@gencode/agents": "0.17.2"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/node": "^22.0.0",
@@ -1 +0,0 @@
1
- import e from"node:http";import t from"node:fs/promises";function n(t={}){let n=t.host??`127.0.0.1`,a=t.port??0,u=t.maxBodyBytes??1048576,p=t.executeRun??s,m=t.prepareSystemRuntime??c,h=t.onLog??(()=>void 0),g=t.pluginsConfig,_=`starting`,v,y,b=null,x=!1,S=()=>void 0,C=new Promise(e=>{S=e});function w(e){x||(x=!0,S(e))}function T(e){_=e,h(`server status changed`,{status:e})}async function E(){let e=b;b=null,!(!e||!e.listening)&&await new Promise((t,n)=>{e.close(e=>{e?n(e):t()})})}async function D(e,t){if(_===`starting`||_===`warming`){f(t,503,{status:_,error:`server is not ready`});return}if(_!==`ready`&&_!==`ready_degraded`){f(t,409,{status:_,error:`server already accepted a run`});return}let n;try{n=i(await d(e,u))}catch(e){f(t,400,{status:_,error:e.message});return}T(`running`),E().catch(e=>{h(`failed to close listener after accepting run`,{error:String(e)})}),f(t,202,{status:_,accepted:!0}),O(n)}async function O(e){let t=0;try{let n=r(e.run,e.env,y);await o(e.env,()=>p(n)),typeof process.exitCode==`number`&&process.exitCode!==0&&(t=process.exitCode),T(`draining`)}catch(e){t=1,h(`run failed`,{error:String(e)}),T(`draining`)}finally{await E().catch(e=>{h(`failed to stop server during drain`,{error:String(e)})}),T(`exiting`),w({exitCode:t})}}async function k(e,t){let r=new URL(e.url??`/`,`http://${n}`);if(e.method===`GET`&&r.pathname===`/healthz`){f(t,200,{status:_});return}if(e.method===`GET`&&r.pathname===`/readyz`){let e=_===`ready`||_===`ready_degraded`;f(t,e?200:503,{status:_,ready:e,degraded:_===`ready_degraded`,warmupError:v});return}if(e.method===`POST`&&r.pathname===`/run`){await D(e,t);return}f(t,404,{status:_,error:`not found`})}async function A(){if(!b){T(`warming`),b=e.createServer((e,t)=>{k(e,t).catch(e=>{f(t,500,{status:_,error:String(e)})})}),await new Promise((e,t)=>{b.once(`error`,t),b.listen(a,n,()=>{b.off(`error`,t),e()})});try{let e=g?await l(g):void 0;e!==void 0&&(y=g),await m({pluginsConfig:e}),_===`warming`&&T(`ready`)}catch(e){v=String(e),h(`system warmup failed; continuing with cold run path`,{error:v}),_===`warming`&&T(`ready_degraded`)}t.requestTimeoutMs&&t.requestTimeoutMs>0&&setTimeout(()=>{(_===`ready`||_===`ready_degraded`)&&E().finally(()=>{T(`exiting`),w({exitCode:1})})},t.requestTimeoutMs).unref()}}function j(){if(!b?.listening)return``;let e=b.address();return`http://${e.address}:${e.port}`}return{start:A,stop:E,done:C,getStatus:()=>_,getUrl:j}}function r(e,t,n){return!n||Object.prototype.hasOwnProperty.call(e,`pluginsConfig`)||t&&Object.prototype.hasOwnProperty.call(t,`AIMAX_PLUGINS_CONFIG`)?e:{...e,pluginsConfig:n}}function i(e){if(!e||typeof e!=`object`)throw Error(`request body must be an object`);let t=e.env;t!==void 0&&a(t);let n=e.run;if(!n||typeof n!=`object`||Array.isArray(n))throw Error(`request body must include run options`);return{env:t,run:n}}function a(e){if(!e||typeof e!=`object`||Array.isArray(e))throw Error(`request env must be an object when provided`);for(let[t,n]of Object.entries(e)){if(!t||t.includes(`=`))throw Error(`request env contains invalid key: ${t}`);if(n!==null&&typeof n!=`string`&&typeof n!=`number`&&typeof n!=`boolean`)throw Error(`request env value for ${t} must be string, number, boolean, or null`)}}async function o(e,t){if(!e||Object.keys(e).length===0)return t();let n=new Map;for(let[t,r]of Object.entries(e))n.set(t,process.env[t]),r===null?delete process.env[t]:process.env[t]=String(r);try{return await t()}finally{for(let[e,t]of n)t===void 0?delete process.env[e]:process.env[e]=t}}async function s(e){await(await u(`@gencode/cli`)).executeRun(e)}async function c(e={}){return(await u(`@gencode/agents/system-runtime`)).prepareSystemRuntime({config:e.pluginsConfig})}async function l(e){let n=await t.readFile(e,`utf-8`);return JSON.parse(n)}const u=Function(`specifier`,`return import(specifier)`);async function d(e,t){let n=[],r=0;for await(let i of e){let e=Buffer.isBuffer(i)?i:Buffer.from(i);if(r+=e.byteLength,r>t)throw Error(`request body is too large`);n.push(e)}let i=Buffer.concat(n).toString(`utf-8`);if(!i.trim())throw Error(`request body must not be empty`);try{return JSON.parse(i)}catch{throw Error(`request body must be valid JSON`)}}function f(e,t,n){e.headersSent||(e.writeHead(t,{"content-type":`application/json; charset=utf-8`}),e.end(`${JSON.stringify(n)}\n`))}export{n as t};