@josephyulei/summon-foundation 0.1.8 → 0.1.9

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  保留真实下载状态与独立确认。基础环境不能安全启动页面时,由 Codex 对话先披露并取得独立批准,再准备专用环境;页面启动后全程同页。具体方法见仓库 `docs/install-with-codex.md`,不能先运行 npx 来准备缺失的 Node。不修改共享 PATH;获取器专用环境及其回执按缓存保留,程序另用随包运行时。发行发现仅需 curl,获取还需 tar;已验证载荷的确认、恢复和卸载不依赖下载工具。
6
6
 
7
- 0.1.8 单页试用入口与 Foundation 0.2.14 的运行引擎共同支持当前用户共用安装及清晰的完成、取消和部分完成反馈。同一页面内保留目录选择、程序和 Skill 独立确认。真实安装、新任务发现和主动告知仍需独立验收。
7
+ 0.1.9 单页试用入口与 Foundation 0.2.15 的运行引擎共同支持当前用户共用安装及清晰的完成、取消和部分完成反馈。同一页面内保留目录选择、程序和 Skill 独立确认。真实安装、新任务发现和主动告知仍需独立验收。
8
8
 
9
9
  首次 URL 持续显示本次流程;确认仅转交本次受控子进程的当前计划,不新开manager页。--acquire仍只读获取;--resume仅在用户明确要求后恢复未完成Skill,不重放程序安装。
10
10
 
@@ -16,7 +16,7 @@ Foundation 的薄获取入口,不包含完整运行包,没有 npm 安装生
16
16
  确认 registry 中存在本版本及对应不可变 Release 后,在具备安装权限的新 Codex 对话粘贴:
17
17
 
18
18
  ```text
19
- npx --yes --package @josephyulei/summon-foundation@0.1.8 summon foundation
19
+ npx --yes --package @josephyulei/summon-foundation@0.1.9 summon foundation
20
20
  ```
21
21
 
22
22
  旧版退出推荐入口;支持边界见[现行支持策略](https://github.com/y15801172513-lang/foundation/blob/main/docs/install-platform-024.md#现行支持策略)。旧不可变版本不修改,不自动迁移或清除旧安装。
package/bin/summon.mjs CHANGED
@@ -11,7 +11,7 @@ import {followMaintenance} from '../lib/maintenance-handoff.mjs';
11
11
  import {installedClient} from '../lib/manager-step.mjs';
12
12
  import {resumeSkillHandoff} from '../lib/resume-handoff.mjs';
13
13
  import {parseSummonArgs} from '../lib/cli-options.mjs';
14
- import {createOperation,saveOperation,readOperation,runtimeObservation} from '../lib/operation-result.mjs';
14
+ import {createOperation,saveOperation,readOperation,runtimeObservation,operationExitCode} from '../lib/operation-result.mjs';
15
15
  import {createJourneyControl} from '../lib/journey-control.mjs';
16
16
  import {inspectEntryEnvironment} from '../lib/environment-check.mjs';
17
17
 
@@ -52,7 +52,7 @@ function stageDirectory(){
52
52
  }
53
53
  let operation=null,stage=null,progressPage=null;
54
54
  const journeyControl=createJourneyControl(()=>operation,patch=>patch?updateOperation(patch):progressPage?.publish());
55
- function updateOperation(patch){if(!operation)return;Object.assign(operation,patch,{updatedAt:new Date().toISOString()});const file=saveOperation(operation,stage);if(file)operation.resultFile=file;progressPage?.publish();console.log(JSON.stringify({status:'FOUNDATION_INSTALL_OPERATION',...operation,resultFile:file,recordSaved:!!file}));}
55
+ function updateOperation(patch){if(!operation)return;Object.assign(operation,patch,{updatedAt:new Date().toISOString()});if(operation.terminal)operation.exitCode=operationExitCode(operation);const file=saveOperation(operation,stage);if(file)operation.resultFile=file;progressPage?.publish();console.log(JSON.stringify({status:'FOUNDATION_INSTALL_OPERATION',...operation,resultFile:file,recordSaved:!!file}));}
56
56
  try{
57
57
  const args=parseSummonArgs(process.argv.slice(2));
58
58
  if(args.help){console.log(help);process.exit(0);}
@@ -74,7 +74,7 @@ try{
74
74
  console.log(JSON.stringify({status:'FOUNDATION_SINGLE_PAGE',url:progressPage.url,operationId:operation.operationId}));
75
75
  const env={...process.env};for(const key of ['NODE_OPTIONS','NODE_PATH','NODE_V8_COVERAGE','NODE_REDIRECT_WARNINGS','NODE_COMPILE_CACHE','NODE_COMPILE_CACHE_PORTABLE','NODE_PRESERVE_SYMLINKS'])delete env[key];
76
76
  const result=await resumeSkillHandoff({file:args.resume,env,journeyControl,onChange:updateOperation});
77
- updateOperation(result);process.exitCode=result.state==='completed'?0:1;
77
+ updateOperation(result);process.exitCode=operationExitCode(result);
78
78
  }else if(maintenance){
79
79
  plainPath(args.root);
80
80
  const env={...process.env};for(const key of ['NODE_OPTIONS','NODE_PATH','NODE_V8_COVERAGE','NODE_REDIRECT_WARNINGS','NODE_COMPILE_CACHE','NODE_COMPILE_CACHE_PORTABLE','NODE_PRESERVE_SYMLINKS'])delete env[key];
@@ -96,7 +96,7 @@ try{
96
96
  updateOperation({phase:'acquired'});
97
97
  }
98
98
  updateOperation(await followMaintenance({operation,kind:operation.kind,candidate,env,onChange:updateOperation,journeyControl}));
99
- process.exitCode=operation.state==='completed'?0:1;
99
+ process.exitCode=operationExitCode(operation);
100
100
  await progressPage.close();progressPage=null;
101
101
  }else if(!args.prepare&&!args.acquire){
102
102
  if(initialEnvironment.state!=='ready'){operation=createOperation();updateOperation({phase:'checking-environment',environment:initialEnvironment});fail('发行查询所需环境无法核实;尚未联网');}
@@ -145,6 +145,6 @@ try{
145
145
  catch(error){updateOperation({state:'partial',phase:'finished',terminal:true,skillRegistered:false,handoffFailure:{code:error.code||'SKILL_HANDOFF_REQUIRES_VERIFICATION',command:error.command||null,exitCode:error.exitCode??null},next:'程序已安装,Skill 接续未完成;保留当前计划与结果,仅核实未完成步骤,不重装程序或重放确认。'});}
146
146
  }
147
147
  if(!operation.terminal)updateOperation({state:'verification-required',terminal:true,childExitCode:ended.code,next:'服务退出不等于成功或取消;只读核验原 session 与 installed 状态,不自动重试'});
148
- process.exitCode=operation.state==='partial'?1:ended.code;
148
+ process.exitCode=operationExitCode(operation);
149
149
  }
150
- }catch(e){const message=String(e.message).replace(/https?:\/\/\S+/g,'[已脱敏网址]').replace(/(?:github_pat_|ghp_|npm_)[A-Za-z0-9_]+/g,'[已脱敏凭据]');updateOperation({state:e.code==='ENTRY_CHOICE_CANCELLED'?'cancelled-no-install':e.code==='ENTRY_CHOICE_EXPIRED'?'expired-no-install':operation?.programState==='completed'?'partial':operation&&operation.installationWrites!=='none'?'verification-required':'failed',terminal:true,...(operation?.programState==='completed'?{failedPhase:operation.phase,phase:'finished'}:{}),errorCode:['ACQUISITION_TRANSPORT_FAILED','ACQUISITION_VALIDATION_FAILED','ENTRY_CHOICE_CANCELLED','ENTRY_CHOICE_EXPIRED'].includes(e.code)?e.code:'INSTALL_ENTRY_FAILED',diagnostic:e.diagnostic||null,next:message+'。先核验旧工具进程已结束及同次结果;保留材料,不自动重试或重放安装确认'});console.error(`错误:${message}`);process.exitCode=1;}finally{if(progressPage)await progressPage.close();}
150
+ }catch(e){const message=String(e.message).replace(/https?:\/\/\S+/g,'[已脱敏网址]').replace(/(?:github_pat_|ghp_|npm_)[A-Za-z0-9_]+/g,'[已脱敏凭据]');updateOperation({state:e.code==='ENTRY_CHOICE_CANCELLED'?'cancelled-no-install':e.code==='ENTRY_CHOICE_EXPIRED'?'expired-no-install':operation?.programState==='completed'?'partial':operation&&operation.installationWrites!=='none'?'verification-required':'failed',terminal:true,...(operation?.programState==='completed'?{failedPhase:operation.phase,phase:'finished'}:{}),errorCode:['ACQUISITION_TRANSPORT_FAILED','ACQUISITION_VALIDATION_FAILED','ENTRY_CHOICE_CANCELLED','ENTRY_CHOICE_EXPIRED'].includes(e.code)?e.code:'INSTALL_ENTRY_FAILED',diagnostic:e.diagnostic||null,next:message+'。先核验旧工具进程已结束及同次结果;保留材料,不自动重试或重放安装确认'});console.error(`错误:${message}`);process.exitCode=operationExitCode(operation);}finally{if(progressPage)await progressPage.close();}
@@ -15,19 +15,20 @@ export function lifecycleContent(record, observations) {
15
15
  else if(cancelled)title='已取消'+verb;
16
16
  else if(expired)title=verb+'确认已到期';
17
17
  else if(environmentBlocked)title='运行环境需要处理';
18
- else if(record.state==='failed'||stepStates.includes('failed'))title=verb+'未成功';
18
+ else if(record.state==='failed'||stepStates.includes('failed'))title=verb+'未完成';
19
19
  else title=anyCompleted?'部分步骤已完成':'操作结果待确认';
20
20
  if(programDone&&kind!=='uninstall'&&!skipped&&!record.skillRegistered)title+=';对话功能'+(['cancelled','skipped'].includes(registration)?'未启用':registration==='failed'?'未处理成功':'尚未完成');
21
21
  }
22
22
  let program=programDone?'程序'+verb+'已完成。'+(kind==='uninstall'?'卸载结果已保存。':record.runtimeHealth==='passed'?'已检查,可以正常打开。':'能否正常打开仍需检查。')
23
23
  :record.installationWrites==='none'||['not-started','cancelled','expired'].includes(record.programState)||['cancelled','expired'].includes(observations.program?.state)?'尚未'+(kind==='install'?'安装 Foundation':'执行程序'+verb)+'。':'程序是否发生变化仍需查看本次结果,请勿重复执行。';
24
24
  if(programDone&&kind==='update'&&record.programResult?.cleanup)program+=record.programResult.cleanup.state==='completed'?'本次下载暂存已按计划清理。':'部分下载文件已保留,不影响已完成的更新。';
25
+ if(!programDone&&record.programState==='failed')program=verb+'未完成。'+(record.rollback==='completed'?'本次程序变更已回退;不表示安装成功。':'是否已回退仍待核实;不要重复执行。');
25
26
  const skill=kind==='uninstall'?(removal==='completed'?'已处理本安装的对话功能文件;修改或未知文件按计划保留。':removal?'对话功能尚未移除成功,原文件保留。':record.hadSkill===false?'本安装没有已登记的对话功能,此次未删除其他 Skill。':'尚未确认是否需要移除对话功能。')
26
27
  :record.skillRegistered===true?'对话功能文件已就位,请在新 Codex 对话中尝试“打开 Foundation”。'
27
28
  :skipped?(kind==='update'?'本次未新增对话功能。':'本次不启用 Codex 对话功能。')
28
29
  :['cancelled','skipped'].includes(registration)?'本次未启用 Codex 对话功能。'
29
30
  :registration==='failed'?'对话功能未处理成功;只需检查这一项,不必重装程序。'
30
- :record.terminal&&!programDone&&(cancelled||expired)?'本次未启用 Codex 对话功能。'
31
+ :record.terminal&&!programDone&&(cancelled||expired||record.programState==='failed')?'本次未安装或启用 Skill;程序失败不会继续安装 Skill。'
31
32
  :observations.material?.state==='completed'?'Skill 已准备,还需要你确认启用到 Codex。'
32
33
  :record.journeyContext?.skillChoice==='selected'?'已选择对话功能,仍需单独确认后才能启用。':'可选择是否启用 Codex 对话功能。';
33
34
  const description=record.terminal?program+' '+skill:kind==='install'?'给当前用户安装一份 Foundation,不同项目按需使用,项目资料各自保管。'+(skipped?'本次不启用对话功能。':'对话功能可选,需另外确认。')
@@ -5,6 +5,14 @@ import crypto from 'node:crypto';
5
5
  export function createOperation() {
6
6
  return {schemaVersion:'1.0.0',operationId:crypto.randomUUID(),pid:process.pid,startedAt:new Date().toISOString(),phase:'discovering',state:'running',terminal:false,installationWrites:'none',skillRegistered:false};
7
7
  }
8
+ // Product outcome, never the confirmation server's exit status, controls the CLI.
9
+ export function operationExitCode(record) {
10
+ if (!record?.terminal) return 1;
11
+ if (record.state === 'completed') return 0;
12
+ if (['cancelled','cancelled-no-install'].includes(record.state)) return 2;
13
+ if (['expired','expired-no-install'].includes(record.state)) return 3;
14
+ return 1;
15
+ }
8
16
  // Observations from the verified runtime, never confirmation or execution authority.
9
17
  export function runtimeObservation(event) {
10
18
  let confirmationUrl;
@@ -13,9 +21,11 @@ export function runtimeObservation(event) {
13
21
  if(['FOUNDATION_SELECTION_BOUND','AWAITING_FOUNDATION_UI_CONFIRMATION'].includes(event.status))return {phase:'awaiting-confirmation',...(event.journeyContext?{journeyContext:event.journeyContext}:{}),sessionId:event.sessionId,planHash:event.planHash,installationWrites:'none',...(confirmationUrl?{confirmationUrl}:{})};
14
22
  if(event.status==='FOUNDATION_OPERATION_STATE'&&['executing','consumed'].includes(event.state))return {phase:'executing',sessionId:event.sessionId,installationWrites:'possible'};
15
23
  if(event.status==='BOOTSTRAP_OPERATION_ENDED'){
16
- const state=['completed','failed','cancelled','expired'].includes(event.state)?event.state:'verification-required';
24
+ const state=event.state==='completed'&&event.result?.ok!==true?'verification-required':['completed','failed','cancelled','expired'].includes(event.state)?event.state:'verification-required';
17
25
  const selectedPending=state==='completed'&&event.journeyContext?.skillChoice==='selected';
18
- return {phase:'runtime-ended',programState:state,state:selectedPending?'awaiting-skill':state,terminal:state!=='verification-required'&&!selectedPending,sessionId:event.sessionId,installationRoot:event.installationRoot,installationWrites:state==='completed'?'runtime-reported-installed':'unknown',runtimeHealth:event.result?.stableLauncherHealth||event.result?.lifecycleResult?.stableLauncherHealth||event.result?.executableHealth||'unknown',journeyContext:event.journeyContext,next:selectedPending?'程序已完成,正在准备所选 Codex 接入的独立确认':'只读核验稳定 installed launcher 或同次 session 结果,不重放确认'};
26
+ const rollback=event.failure?.details?.rollback||'unknown';
27
+ const failureNext=rollback==='completed'?'本次程序变更已回退;Skill 未安装。保留本次记录,在原对话查看健康检查错误,修复后再申请新计划;不要重放旧确认。':'回退情况待核实;Skill 未安装。保留本次记录,在原对话核实健康检查与恢复状态;不要自动重试。';
28
+ return {phase:'runtime-ended',programState:state,state:selectedPending?'awaiting-skill':state,terminal:state!=='verification-required'&&!selectedPending,sessionId:event.sessionId,installationRoot:event.installationRoot,installationWrites:state==='completed'?'runtime-reported-installed':rollback==='completed'?'rolled-back':'unknown',runtimeHealth:event.result?.stableLauncherHealth||event.result?.lifecycleResult?.stableLauncherHealth||event.result?.executableHealth||'unknown',failure:event.failure||null,rollback,journeyContext:event.journeyContext,next:selectedPending?'程序已完成,正在准备所选 Codex 接入的独立确认':state==='failed'?failureNext:'只读核验稳定 installed launcher 或同次 session 结果,不重放确认'};
19
29
  }
20
30
  if(['cancelled-no-install','expired-no-install','shutdown-no-install'].includes(event.state))return {phase:'directory-selection-ended',state:event.state,terminal:true,installationWrites:'none'};
21
31
  return null;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@josephyulei/summon-foundation",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@josephyulei/summon-foundation",
9
- "version": "0.1.8",
9
+ "version": "0.1.9",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@sigstore/bundle": "4.0.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@josephyulei/summon-foundation",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Prepare a verified Foundation release for an explicitly confirmed Codex installation",
5
5
  "type": "module",
6
6
  "bin": {"summon": "bin/summon.mjs"},