niuma-codex 0.0.1-beta.21 → 0.0.1-beta.22

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
@@ -28,12 +28,14 @@ npx niuma-codex@latest --background --restart
28
28
  npx niuma-codex@latest daemon-stop
29
29
  ```
30
30
 
31
- install-app 入口安装/打开 Niuma Lite,使用独立目录中的 daemon,退出应用会停止其自有 daemon;缺少发行清单时明确提示暂不可安装。Electron 完整版仍独立提供。以下后台换代规则适用于普通配对入口(含无参数)与显式后台。关闭终端或配对网页不会停止独立后台 daemon。启动时同时核对当前发布版本与 Relay 地址:两者一致才复用 daemon;版本不同、旧实例未报告版本或地址不一致时,自动停止旧后台服务,等待退出后使用本次版本与配置启动。根网页、后台与终端二维码入口均执行此规则;这会中断当前连接与请求。同版本内修改配置时仍须显式重启。可用 `npx niuma-codex@<version> daemon-status --json` 查看 `release_version`,确认后台实际运行的发布版本。不要在后台服务运行期间手动删除它所在的 npm 缓存目录。
31
+ install-app 入口安装/打开 Niuma Lite,使用独立目录中的 daemon,退出应用会停止其自有 daemon;缺少发行清单时明确提示暂不可安装。Electron 完整版仍独立提供。以下后台换代规则适用于普通配对入口(含无参数)与显式后台。关闭终端或配对网页不会停止独立后台 daemon。启动时同时核对当前发布版本与 Relay 地址:两者一致才复用 daemon;版本不同、旧实例未报告版本或地址不一致时,自动停止旧后台服务,等待退出后使用本次版本与配置启动。根网页、后台与终端 URI 排障入口均执行此规则;这会中断当前连接与请求。同版本内修改配置时仍须显式重启。可用 `npx niuma-codex@<version> daemon-status --json` 查看 `release_version`,确认后台实际运行的发布版本。不要在后台服务运行期间手动删除它所在的 npm 缓存目录。
32
32
 
33
33
  发布入口不读取工作目录或开发仓库的 `.env`。Relay 地址按本次 `--relay-origin`、`NIUMA_RELAY_ORIGIN`、`NIUMA_RELAY_PUBLIC_URL` 的顺序选择;均未配置时默认使用 `https://relay.niumacoding.com`。源码开发的兜底地址仍是本机 Server。启动和重启都不读取历史地址缓存,也不继承旧 daemon 的地址。自建服务须在启动时保留显式参数或环境配置。地址相同时不会因连接失败自动重启或切换服务。服务可用性独立于 npm 包安装。
34
34
 
35
35
  Push 地址独立于 Relay:`NIUMA_PUSH_SERVER_ORIGIN` 非空时优先使用该值,未设置或为空白时,发布包默认使用 `https://api.niumacoding.com`;源码开发仍使用本机 Server。推送登记要求 HTTPS,服务故障不自动切换地址。自建服务须显式配置 Push 地址,并与 Server 的同名配置一致,该地址参与请求和绑定证明的签名校验。同版本内修改 Push 配置后,需要使用 `--background --restart` 载入配置;运行不同发布版本时自动重启载入新版默认值。推送失败本身不会触发重启。
36
36
 
37
+ Desktop 的独立附件传输在 `NIUMA_ATTACHMENT_TRANSFER_ENABLED` 未设置时默认开启;普通 npx 启动可显式设置 `false` 关闭。Relay 附件数据通道还要求 Server 独立启用该能力,且两端承载和客户端能力协商均就绪。同版本修改此变量后需使用 `--background --restart` 载入配置。登录自启动只保存下述白名单配置,不保存此变量,登录后按默认值开启。
38
+
37
39
  iOS 配对成功不等于推送登记成功:进入已认证的会话页面后,需完成通知授权、APNs Token 注册和设备接收关系登记,实际签名环境须由 Server 支持。已有 iOS 推送登记不会随 Desktop 默认地址改变而自动迁移。
38
40
 
39
41
  旧实例若仍连接错误的本机地址,可在无运行任务时显式执行 `npx niuma-codex@latest --background --restart --relay-origin https://relay.niumacoding.com`,再刷新配对页。二维码要求 Relay 完成认证且支持 Relay v2 / Pairing V5;仅安装 Codex CLI 不会安装本机 Niuma Server。
@@ -6,5 +6,5 @@
6
6
  第三方 JavaScript 与原生运行库作为 npm dependencies 单独安装,未合并到
7
7
  自有 JavaScript 产物中。各库适用其随包提供的许可证和版权声明,包括:
8
8
  @noble/curves、canonicalize、dotenv、bootstrap、chart.js、
9
- mdast-util-from-markdown、qrcode、qrcode-terminal、sharp、tar(BlueOak-1.0.0)、ws、zod。
9
+ mdast-util-from-markdown、qrcode、sharp、tar(BlueOak-1.0.0)、ws、zod。
10
10
  其传递依赖同样保留各自许可证;本包的 Apache-2.0 不替代这些许可。
@@ -13,7 +13,7 @@
13
13
  </nav><p class="trust">仅允许你信任的设备连接。</p>
14
14
  </aside>
15
15
  <div class="content">
16
- <section id="settings-panel" class="settings-panel" aria-labelledby="settings-title" hidden><header class="page-heading"><h2 id="settings-title">设置</h2><p>管理这台电脑上的 Niuma。</p></header><h3 class="settings-group-title">启动与运行</h3><div id="autostart-controls" class="autostart-row"><div><label id="autostart-label" for="autostart-enabled">登录后自动启动 Niuma</label><p id="autostart-description">登录这台 Mac 后自动启动后台服务。关闭后,当前服务仍会继续运行。</p><p id="autostart-hint" class="settings-hint">首次开启需要下载运行文件。</p></div><input id="autostart-enabled" type="checkbox" role="switch" aria-describedby="autostart-description" disabled></div><p id="autostart-message" role="status" aria-live="polite">正在读取设置…</p><button id="autostart-retry" class="text-button" hidden>重试</button>
16
+ <section id="settings-panel" class="settings-panel" aria-labelledby="settings-title" hidden><header class="page-heading"><h2 id="settings-title">设置</h2><p>管理这台电脑上的 Niuma。</p></header><h3 class="settings-group-title">启动与运行</h3><div id="autostart-controls" class="autostart-row"><div><label id="autostart-label" for="autostart-enabled">登录后自动启动 Niuma</label><p id="autostart-description">登录这台 Mac 后自动启动后台服务。关闭后,当前服务仍会继续运行。</p><p id="autostart-hint" class="settings-hint">首次开启需要下载运行文件。</p></div><input id="autostart-enabled" type="checkbox" role="switch" aria-describedby="autostart-description" disabled></div><p id="autostart-message" role="status" aria-live="polite">正在读取设置…</p><div class="settings-actions"><button id="autostart-open-settings" class="text-button" hidden>打开系统设置</button><button id="autostart-retry" class="text-button" hidden>重试</button><button id="autostart-cancel" class="text-button" hidden>取消自启动</button></div>
17
17
  <section id="app-about" class="app-about" aria-labelledby="app-about-title" hidden><h3 id="app-about-title" class="settings-group-title">关于 Niuma Lite</h3><dl class="app-version"><dt>版本</dt><dd id="app-version"></dd></dl></section></section>
18
18
  <div id="device-workspace">
19
19
  <div id="home-intro"></div>
@@ -2,6 +2,8 @@
2
2
  export function mountAutostartSettings(doc,win,request){
3
3
  const $=id=>doc.getElementById(id);
4
4
  const bridge=win.niumaLoginItem;
5
+ const approvalMessage='请前往「系统设置 → 通用 → 登录项与扩展」,允许 Niuma Lite 登录时打开。返回后将自动检查状态。';
6
+ const errorMessage=(error,fallback)=>typeof error==='string'?error:error?.message||fallback;
5
7
  // 仅 Lite 宿主提供统一版本;静态信息不受登录项读取失败影响。
6
8
  const about=$('app-about');
7
9
  if(about){
@@ -20,12 +22,13 @@ export function mountAutostartSettings(doc,win,request){
20
22
  if(init.method==='POST')await bridge.set(JSON.parse(init.body).enabled);
21
23
  const current=await bridge.read();
22
24
  // 宿主桥接返回实际登录项状态,映射到页面共用的系统启用字段。
23
- return {ok:true,json:async()=>({code:0,data:{supported:current.available,registered:current.enabled||current.requiresApproval===true,loaded:current.enabled,available:current.available,operation:null,notice:current.message,reason:'请安装 Niuma 应用后设置登录自启动'}})};
25
+ return {ok:true,json:async()=>({code:0,data:{supported:current.available,registered:current.enabled||current.requiresApproval===true,loaded:current.enabled,available:current.available&&current.enabled,requiresApproval:current.requiresApproval===true,operation:null,notice:current.message,reason:'请安装 Niuma 应用后设置登录自启动'}})};
24
26
  }
25
- let state=null,inFlight=false,changing=false,generation=0,timer=null;
27
+ let state=null,inFlight=false,changing=false,generation=0,timer=null,opening=false;
26
28
  const visible=()=>!$('settings-panel').hidden&&!doc.hidden;
27
29
  // 注册文件保留不代表系统允许启动;未知状态只能刷新,不能据此修改注册。
28
30
  const systemUnavailable=()=>state?.registered&&state.loaded!==true;
31
+ const approvalPending=()=>!!bridge&&state?.requiresApproval===true;
29
32
  const systemUnknown=()=>state?.registered&&typeof state.loaded!=='boolean';
30
33
  function stop(){generation++;if(timer!==null)win.clearTimeout(timer);timer=null;}
31
34
  function render(message=''){
@@ -38,9 +41,14 @@ export function mountAutostartSettings(doc,win,request){
38
41
  $('autostart-enabled').disabled=!state||!state.supported||systemUnknown()||working||inFlight;
39
42
  $('autostart-message').textContent=message||(working?(operation?.target_enabled===false?'正在关闭…':'正在开启…'):
40
43
  !state?'正在读取设置…':!state.supported?(state.reason||'当前环境不支持登录自启动'):
41
- state.notice||(systemUnknown()?'无法确认系统登录项状态,请刷新重试。':systemUnavailable()?(bridge?'请在系统设置的登录项中允许 Niuma 登录时打开,然后刷新状态。':'自启动尚未获系统启用,请检查系统设置中的登录项并允许 Niuma 在后台运行。'):
44
+ state.notice||(systemUnknown()?'无法确认系统登录项状态,请刷新重试。':systemUnavailable()?(bridge?approvalMessage:state.reason||'请前往「系统设置 → 通用 → 登录项与扩展」,在「允许在后台」中开启 Niuma,然后返回此页刷新状态。'):
42
45
  state.registered&&!state.available?'已配置,但暂不可用。请重新配置。':state.registered?'已开启':'未开启'));
43
46
  $('autostart-retry').hidden=working||(!message&&!(state?.registered&&!state.available));
47
+ // 待授权时开关按系统实际值显示关闭,提供独立取消入口以撤回已有登记。
48
+ const cancel=$('autostart-cancel');
49
+ if(cancel){cancel.hidden=!state?.supported||!systemUnavailable()||systemUnknown()||(!!bridge&&!approvalPending());cancel.disabled=working||inFlight;}
50
+ const open=$('autostart-open-settings');
51
+ if(open){open.hidden=!approvalPending()||typeof bridge?.openSettings!=='function';open.disabled=working||inFlight||opening;}
44
52
  $('autostart-retry').textContent=systemUnavailable()?'刷新状态':state?.registered&&!state.available?'重新配置':'重试';
45
53
  }
46
54
  async function load(){
@@ -55,7 +63,9 @@ export function mountAutostartSettings(doc,win,request){
55
63
  }catch(error){if(owner===generation){state=null;render(error.message||'无法读取设置,请重试');}}
56
64
  finally{
57
65
  inFlight=false;
58
- if(owner===generation){$('autostart-enabled').disabled=!state||!state.supported||systemUnknown()||changing||state.operation?.state==='running';
66
+ if(owner===generation){const cancel=$('autostart-cancel');if(cancel)cancel.disabled=changing||state?.operation?.state==='running';
67
+ const open=$('autostart-open-settings');if(open)open.disabled=opening||changing||state?.operation?.state==='running';
68
+ $('autostart-enabled').disabled=!state||!state.supported||systemUnknown()||changing||state.operation?.state==='running';
59
69
  if(visible()&&state?.operation?.state==='running')timer=win.setTimeout(()=>{timer=null;void load();},1000);
60
70
  }else if(visible())void load();
61
71
  }
@@ -68,7 +78,7 @@ export function mountAutostartSettings(doc,win,request){
68
78
  const response=await settingsRequest({method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({enabled})});
69
79
  const payload=await response.json();
70
80
  if(!response.ok||payload.code!==0)message=payload.message||'设置失败,请重试';
71
- }catch(error){message=bridge?(error.message||'设置失败,请重试'):'连接中断,正在核对实际设置,请勿重复操作';}
81
+ }catch(error){message=bridge?errorMessage(error,'设置失败,请重试'):'连接中断,正在核对实际设置,请勿重复操作';}
72
82
  finally{changing=false;await load();if(message&&visible())render(message);}
73
83
  }
74
84
  // 导航只切换容器可见性,保留设备与配对状态;业务响应不能抢回当前页面。
@@ -82,6 +92,14 @@ export function mountAutostartSettings(doc,win,request){
82
92
  }
83
93
  $('settings-toggle').onclick=()=>navigate(true);
84
94
  $('devices-nav').onclick=()=>navigate(false);
95
+ const cancel=$('autostart-cancel');if(cancel)cancel.onclick=()=>void change(false);
96
+ const open=$('autostart-open-settings');
97
+ if(open)open.onclick=async()=>{
98
+ if(opening||changing||inFlight||!approvalPending()||typeof bridge?.openSettings!=='function')return;
99
+ opening=true;render();let message='';
100
+ try{await bridge.openSettings();}catch(error){message=errorMessage(error,'无法打开系统设置,请按提示手动打开。');}
101
+ finally{opening=false;render(message);}
102
+ };
85
103
  $('autostart-enabled').onchange=()=>{const enabled=$('autostart-enabled').checked;void change(enabled);};
86
104
  $('autostart-retry').onclick=()=>{
87
105
  // 系统授权改变后只重新查询,避免刷新按钮重新注册并覆盖用户在系统中的选择。
@@ -69,7 +69,7 @@
69
69
  .sidebar .trust{font-size:13px;margin-top:32px;padding-top:24px;border-top:1px solid var(--line)}
70
70
  .content{padding:40px 48px 64px}
71
71
  .list-heading{flex-wrap:wrap;gap:24px;margin-bottom:24px}
72
- .list-actions{display:flex;align-items:center;flex-wrap:wrap;gap:20px}
72
+ .list-actions,.settings-actions{display:flex;align-items:center;flex-wrap:wrap;gap:20px}
73
73
  .page-heading{margin-bottom:40px}
74
74
  .page-heading p{margin-top:12px}
75
75
  .settings-group-title{font-size:16px;font-weight:500;color:var(--muted);padding-bottom:16px;border-bottom:1px solid var(--line)}