shennian 0.4.0 → 0.4.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/dist/native/macos-background-client/Shennian.app/Contents/CodeResources +0 -0
- package/dist/native/macos-background-client/Shennian.app/Contents/Info.plist +17 -0
- package/dist/native/macos-background-client/Shennian.app/Contents/MacOS/ShennianClientLauncher +0 -0
- package/dist/native/macos-background-client/Shennian.app/Contents/Resources/en.lproj/InfoPlist.strings +2 -0
- package/dist/native/macos-background-client/Shennian.app/Contents/Resources/zh-Hans.lproj/InfoPlist.strings +2 -0
- package/dist/native/macos-background-client/Shennian.app/Contents/_CodeSignature/CodeResources +153 -0
- package/dist/publish-build-manifest.json +8 -8
- package/dist/src/commands/daemon.d.ts +4 -0
- package/dist/src/commands/daemon.js +21 -17
- package/dist/src/commands/pair-browser.js +1 -1
- package/dist/src/room/device-authorization-client.d.ts +2 -0
- package/dist/src/room/managed-prompt-composer.d.ts +1 -1
- package/dist/src/room/managed-prompt-composer.js +2 -1
- package/dist/src/upgrade/engine.d.ts +1 -0
- package/dist/src/upgrade/engine.js +2 -2
- package/package.json +3 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key><string>en</string>
|
|
6
|
+
<key>CFBundleDisplayName</key><string>Shennian</string>
|
|
7
|
+
<key>CFBundleExecutable</key><string>ShennianClientLauncher</string>
|
|
8
|
+
<key>CFBundleIdentifier</key><string>net.shennian.client.background-service</string>
|
|
9
|
+
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
|
|
10
|
+
<key>CFBundleName</key><string>Shennian</string>
|
|
11
|
+
<key>CFBundlePackageType</key><string>APPL</string>
|
|
12
|
+
<key>CFBundleShortVersionString</key><string>1.0.0</string>
|
|
13
|
+
<key>CFBundleVersion</key><string>1.0.0</string>
|
|
14
|
+
<key>LSBackgroundOnly</key><true/>
|
|
15
|
+
<key>LSMinimumSystemVersion</key><string>13.0</string>
|
|
16
|
+
</dict>
|
|
17
|
+
</plist>
|
package/dist/native/macos-background-client/Shennian.app/Contents/MacOS/ShennianClientLauncher
ADDED
|
Binary file
|
package/dist/native/macos-background-client/Shennian.app/Contents/_CodeSignature/CodeResources
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>files</key>
|
|
6
|
+
<dict>
|
|
7
|
+
<key>Resources/en.lproj/InfoPlist.strings</key>
|
|
8
|
+
<dict>
|
|
9
|
+
<key>hash</key>
|
|
10
|
+
<data>
|
|
11
|
+
7cZ/3Y+z3FLOqySef5/rGgdk+hU=
|
|
12
|
+
</data>
|
|
13
|
+
<key>optional</key>
|
|
14
|
+
<true/>
|
|
15
|
+
</dict>
|
|
16
|
+
<key>Resources/zh-Hans.lproj/InfoPlist.strings</key>
|
|
17
|
+
<dict>
|
|
18
|
+
<key>hash</key>
|
|
19
|
+
<data>
|
|
20
|
+
6MKN0tNN2Z8t8wIkKiANNKgscLY=
|
|
21
|
+
</data>
|
|
22
|
+
<key>optional</key>
|
|
23
|
+
<true/>
|
|
24
|
+
</dict>
|
|
25
|
+
</dict>
|
|
26
|
+
<key>files2</key>
|
|
27
|
+
<dict>
|
|
28
|
+
<key>Resources/en.lproj/InfoPlist.strings</key>
|
|
29
|
+
<dict>
|
|
30
|
+
<key>hash2</key>
|
|
31
|
+
<data>
|
|
32
|
+
FJaLoD8f3R/s4Tvbgbvcrb9uzFLfPBACRdeL+bpiUtw=
|
|
33
|
+
</data>
|
|
34
|
+
<key>optional</key>
|
|
35
|
+
<true/>
|
|
36
|
+
</dict>
|
|
37
|
+
<key>Resources/zh-Hans.lproj/InfoPlist.strings</key>
|
|
38
|
+
<dict>
|
|
39
|
+
<key>hash2</key>
|
|
40
|
+
<data>
|
|
41
|
+
B/tCw00PlOTxARULQMz6SavBh8IU6/M0b8GXT253tC0=
|
|
42
|
+
</data>
|
|
43
|
+
<key>optional</key>
|
|
44
|
+
<true/>
|
|
45
|
+
</dict>
|
|
46
|
+
</dict>
|
|
47
|
+
<key>rules</key>
|
|
48
|
+
<dict>
|
|
49
|
+
<key>^Resources/</key>
|
|
50
|
+
<true/>
|
|
51
|
+
<key>^Resources/.*\.lproj/</key>
|
|
52
|
+
<dict>
|
|
53
|
+
<key>optional</key>
|
|
54
|
+
<true/>
|
|
55
|
+
<key>weight</key>
|
|
56
|
+
<real>1000</real>
|
|
57
|
+
</dict>
|
|
58
|
+
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
59
|
+
<dict>
|
|
60
|
+
<key>omit</key>
|
|
61
|
+
<true/>
|
|
62
|
+
<key>weight</key>
|
|
63
|
+
<real>1100</real>
|
|
64
|
+
</dict>
|
|
65
|
+
<key>^Resources/Base\.lproj/</key>
|
|
66
|
+
<dict>
|
|
67
|
+
<key>weight</key>
|
|
68
|
+
<real>1010</real>
|
|
69
|
+
</dict>
|
|
70
|
+
<key>^version.plist$</key>
|
|
71
|
+
<true/>
|
|
72
|
+
</dict>
|
|
73
|
+
<key>rules2</key>
|
|
74
|
+
<dict>
|
|
75
|
+
<key>.*\.dSYM($|/)</key>
|
|
76
|
+
<dict>
|
|
77
|
+
<key>weight</key>
|
|
78
|
+
<real>11</real>
|
|
79
|
+
</dict>
|
|
80
|
+
<key>^(.*/)?\.DS_Store$</key>
|
|
81
|
+
<dict>
|
|
82
|
+
<key>omit</key>
|
|
83
|
+
<true/>
|
|
84
|
+
<key>weight</key>
|
|
85
|
+
<real>2000</real>
|
|
86
|
+
</dict>
|
|
87
|
+
<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
|
|
88
|
+
<dict>
|
|
89
|
+
<key>nested</key>
|
|
90
|
+
<true/>
|
|
91
|
+
<key>weight</key>
|
|
92
|
+
<real>10</real>
|
|
93
|
+
</dict>
|
|
94
|
+
<key>^.*</key>
|
|
95
|
+
<true/>
|
|
96
|
+
<key>^Info\.plist$</key>
|
|
97
|
+
<dict>
|
|
98
|
+
<key>omit</key>
|
|
99
|
+
<true/>
|
|
100
|
+
<key>weight</key>
|
|
101
|
+
<real>20</real>
|
|
102
|
+
</dict>
|
|
103
|
+
<key>^PkgInfo$</key>
|
|
104
|
+
<dict>
|
|
105
|
+
<key>omit</key>
|
|
106
|
+
<true/>
|
|
107
|
+
<key>weight</key>
|
|
108
|
+
<real>20</real>
|
|
109
|
+
</dict>
|
|
110
|
+
<key>^Resources/</key>
|
|
111
|
+
<dict>
|
|
112
|
+
<key>weight</key>
|
|
113
|
+
<real>20</real>
|
|
114
|
+
</dict>
|
|
115
|
+
<key>^Resources/.*\.lproj/</key>
|
|
116
|
+
<dict>
|
|
117
|
+
<key>optional</key>
|
|
118
|
+
<true/>
|
|
119
|
+
<key>weight</key>
|
|
120
|
+
<real>1000</real>
|
|
121
|
+
</dict>
|
|
122
|
+
<key>^Resources/.*\.lproj/locversion.plist$</key>
|
|
123
|
+
<dict>
|
|
124
|
+
<key>omit</key>
|
|
125
|
+
<true/>
|
|
126
|
+
<key>weight</key>
|
|
127
|
+
<real>1100</real>
|
|
128
|
+
</dict>
|
|
129
|
+
<key>^Resources/Base\.lproj/</key>
|
|
130
|
+
<dict>
|
|
131
|
+
<key>weight</key>
|
|
132
|
+
<real>1010</real>
|
|
133
|
+
</dict>
|
|
134
|
+
<key>^[^/]+$</key>
|
|
135
|
+
<dict>
|
|
136
|
+
<key>nested</key>
|
|
137
|
+
<true/>
|
|
138
|
+
<key>weight</key>
|
|
139
|
+
<real>10</real>
|
|
140
|
+
</dict>
|
|
141
|
+
<key>^embedded\.provisionprofile$</key>
|
|
142
|
+
<dict>
|
|
143
|
+
<key>weight</key>
|
|
144
|
+
<real>20</real>
|
|
145
|
+
</dict>
|
|
146
|
+
<key>^version\.plist$</key>
|
|
147
|
+
<dict>
|
|
148
|
+
<key>weight</key>
|
|
149
|
+
<real>20</real>
|
|
150
|
+
</dict>
|
|
151
|
+
</dict>
|
|
152
|
+
</dict>
|
|
153
|
+
</plist>
|
|
@@ -191,8 +191,8 @@
|
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
193
|
"file": "src/commands/daemon.js",
|
|
194
|
-
"beforeBytes":
|
|
195
|
-
"afterBytes":
|
|
194
|
+
"beforeBytes": 46411,
|
|
195
|
+
"afterBytes": 22150
|
|
196
196
|
},
|
|
197
197
|
{
|
|
198
198
|
"file": "src/commands/integration.js",
|
|
@@ -216,8 +216,8 @@
|
|
|
216
216
|
},
|
|
217
217
|
{
|
|
218
218
|
"file": "src/commands/pair-browser.js",
|
|
219
|
-
"beforeBytes":
|
|
220
|
-
"afterBytes":
|
|
219
|
+
"beforeBytes": 6847,
|
|
220
|
+
"afterBytes": 3822
|
|
221
221
|
},
|
|
222
222
|
{
|
|
223
223
|
"file": "src/commands/pair-qr.js",
|
|
@@ -506,8 +506,8 @@
|
|
|
506
506
|
},
|
|
507
507
|
{
|
|
508
508
|
"file": "src/room/managed-prompt-composer.js",
|
|
509
|
-
"beforeBytes":
|
|
510
|
-
"afterBytes":
|
|
509
|
+
"beforeBytes": 9461,
|
|
510
|
+
"afterBytes": 9832
|
|
511
511
|
},
|
|
512
512
|
{
|
|
513
513
|
"file": "src/room/managed-room-binding.js",
|
|
@@ -716,8 +716,8 @@
|
|
|
716
716
|
},
|
|
717
717
|
{
|
|
718
718
|
"file": "src/upgrade/engine.js",
|
|
719
|
-
"beforeBytes":
|
|
720
|
-
"afterBytes":
|
|
719
|
+
"beforeBytes": 16698,
|
|
720
|
+
"afterBytes": 7021
|
|
721
721
|
},
|
|
722
722
|
{
|
|
723
723
|
"file": "src/upgrade/scheduler.js",
|
|
@@ -88,6 +88,10 @@ export declare function getDaemonStatus(opts?: {
|
|
|
88
88
|
}): DaemonStatus;
|
|
89
89
|
export declare function buildDaemonSpawnOptions(launch: DetachedLaunchSpec, logFd: number, env?: NodeJS.ProcessEnv): Parameters<typeof spawn>[2];
|
|
90
90
|
export declare function captureEnvForService(): Record<string, string>;
|
|
91
|
+
export declare function buildMacLaunchdPlist(input?: {
|
|
92
|
+
launch?: ServiceLaunchSpec;
|
|
93
|
+
brandedLauncherPath?: string | null;
|
|
94
|
+
}): string;
|
|
91
95
|
export declare function buildSystemdUnit(): string;
|
|
92
96
|
type LaunchdCommandExecutor = (command: string) => void;
|
|
93
97
|
export declare function getLaunchdServiceTarget(uid?: number | string): string;
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
import c from"chalk";import
|
|
2
|
-
`)}function
|
|
3
|
-
<string>${T(
|
|
4
|
-
`),
|
|
5
|
-
`)
|
|
1
|
+
import c from"chalk";import i from"node:fs";import s from"node:path";import d from"node:os";import{execSync as u,spawn as he,spawnSync as ye}from"node:child_process";import{randomUUID as V}from"node:crypto";import{fileURLToPath as ge}from"node:url";import{getShennianDir as we,loadConfig as G,resolveShennianPath as y,saveConfig as ve}from"../config/index.js";import{buildAugmentedPath as Ee}from"../env-path.js";import{buildWindowsLauncherCommand as Ae,buildWindowsScheduledTaskCommands as Pe,buildWindowsScheduledTaskXml as ke,buildWindowsStartupVbs as De,escapeXml as T,isWindowsCmdScript as Ie,quoteCmdArg as J,quoteSystemdArg as Ne,suspendWindowsScheduledTask as be}from"./daemon-windows.js";import{waitForDaemonReadyStatus as $}from"./daemon-start-wait.js";import{findRunningWindowsDaemonProcessIds as Re,isShennianRunServiceCommand as xe}from"./daemon-process.js";import{getCurrentVersion as K}from"../upgrade/engine.js";import{buildWindowsLauncherCommand as _n,buildWindowsScheduledTaskCommands as On,buildWindowsScheduledTaskSuspendCommands as Tn,buildWindowsScheduledTaskXml as $n,buildWindowsStartupVbs as Cn,suspendWindowsScheduledTask as Hn}from"./daemon-windows.js";import{isShennianRunServiceCommand as Un}from"./daemon-process.js";const X=s.dirname(ge(import.meta.url)),w=we(),v=y("daemon.pid"),p=y("daemon.log"),C=y("remote-access.disabled"),x=y("daemon-launcher.json"),q=s.resolve(X,"../../bin/shennian.js"),Y=process.execPath,z=new Set(["PATH","HOME","USERPROFILE","HOMEDRIVE","HOMEPATH","USERNAME","USERDOMAIN","COMPUTERNAME","USER","LOGNAME","SHELL","TMPDIR","LANG","LC_ALL","LC_CTYPE","SSH_AUTH_SOCK","XDG_CONFIG_HOME","XDG_DATA_HOME","TEMP","TMP","APPDATA","LOCALAPPDATA","SHENNIAN_DESKTOP_SERVER_URL","SHENNIAN_WECHAT_CHANNEL_HELPER_DIR","SHENNIAN_HOME","SHENNIAN_ACCOUNT_NAMESPACE_ID","SHENNIAN_NATIVE_FUSION_DISABLED","SHENNIAN_WECHAT_DELIVERABILITY_TRACE"]);function Le(e){return z.has(e)}function m(){const e=d.platform();return e==="darwin"||e==="linux"||e==="win32"?e:"linux"}function H(e){const n=e.replace(/\\/g,"/").toLowerCase(),t=d.tmpdir().replace(/\\/g,"/").toLowerCase();return n.includes("/_npx/")||n.includes("/npm-cache/_npx/")||n.includes("/pnpm/dlx/")||n.startsWith(t.endsWith("/")?t:`${t}/`)}function _e(e){return i.existsSync(e.scriptPath)&&!H(e.scriptPath)?{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}:e.shennianCommandPath&&!H(e.shennianCommandPath)?{command:e.shennianCommandPath,args:["run-service"],mode:"global-shim"}:e.npxPath?{command:e.npxPath,args:["--yes","shennian","run-service"],mode:"npx"}:{command:e.nodeExec,args:[e.scriptPath,"run-service"],mode:"direct"}}function Oe(e){const n=e.trim();if(!n)return null;if(n.startsWith("{"))try{const r=JSON.parse(n),o=Number(r.pid);return!Number.isInteger(o)||o<=0?null:{pid:o,...typeof r.instanceId=="string"?{instanceId:r.instanceId}:{},...typeof r.version=="string"?{version:r.version}:{},...r.launcher==="desktop-managed"||r.launcher==="global-cli"||r.launcher==="unknown"?{launcher:r.launcher}:{},...typeof r.startedAt=="string"?{startedAt:r.startedAt}:{},...r.adopted===!0?{adopted:!0}:{}}}catch{return null}const t=parseInt(n,10);return isNaN(t)?null:{pid:t}}function D(){try{return Oe(i.readFileSync(v,"utf-8"))}catch{return null}}function A(e){try{return process.kill(e,0),!0}catch{return!1}}function Q(e,n=3e3){const t=Date.now();for(;Date.now()-t<n;){if(!A(e))return!0;Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,100)}return!A(e)}function Te(){return i.existsSync(C)}function $e(){try{i.unlinkSync(C)}catch{}}function Ce(e,n){const t=s.dirname(e),r=`${e}.${process.pid}.${V()}.tmp`;i.mkdirSync(t,{recursive:!0});let o=null;try{o=i.openSync(r,"w",384),i.writeSync(o,n,void 0,"utf8"),i.fsyncSync(o),i.closeSync(o),o=null,i.renameSync(r,e);try{const a=i.openSync(t,"r");try{i.fsyncSync(a)}finally{i.closeSync(a)}}catch{}}finally{o!==null&&i.closeSync(o);try{i.unlinkSync(r)}catch{}}}function He(e={}){const n=e.disabledAt??new Date().toISOString(),t=e.markerFile??C,r=e.platform??m(),o=e.servicePresent??W(r),a=e.execCommand??(l=>{u(l,{stdio:"pipe",windowsHide:!0})});if(Ce(t,n),!o)return{disabledAt:n,autoStartDisabled:!0};try{return a(r==="darwin"?`launchctl disable "${k()}"`:r==="linux"?"systemctl --user disable shennian":`schtasks /change /tn "${b}" /disable`),{disabledAt:n,autoStartDisabled:!0}}catch(l){return{disabledAt:n,autoStartDisabled:!1,autoStartError:l instanceof Error?l.message:String(l)}}}function Me(e={}){const n=e.platform??m();if(!(e.servicePresent??W(n)))return{serviceStopped:!0};const r=e.execCommand??(o=>{u(o,{stdio:"pipe",windowsHide:!0})});try{return r(n==="darwin"?`launchctl bootout "${k()}"`:n==="linux"?"systemctl --user stop shennian":`schtasks /end /tn "${b}"`),{serviceStopped:!0}}catch(o){return{serviceStopped:!1,error:o instanceof Error?o.message:String(o)}}}function Z(){return"global-cli"}function Ue(){return`${process.pid}-${Date.now()}-${V()}`}function je(e,n,t={}){i.mkdirSync(w,{recursive:!0}),i.writeFileSync(v,JSON.stringify({pid:e,instanceId:n,...t.version?{version:t.version}:{},launcher:t.launcher??Z(),...t.adopted?{adopted:!0}:{},startedAt:new Date().toISOString()},null,2))}function bn(e,n){const t=D();if(!(t?.pid!==e||t.instanceId!==n))try{i.unlinkSync(v)}catch{}}function ee(e,n=Z(),t){i.mkdirSync(w,{recursive:!0}),i.writeFileSync(x,JSON.stringify({pid:e,launcher:n,...t?{instanceId:t}:{},updatedAt:new Date().toISOString()},null,2))}function We(e){if(e)try{if(JSON.parse(i.readFileSync(x,"utf-8")).instanceId!==e)return}catch{return}try{i.unlinkSync(x)}catch{}}function Fe(e){e&&ee(e)}function Be(e,n){if(!e||!n)return"unknown";try{const t=JSON.parse(i.readFileSync(x,"utf-8"));if(t.pid!==e)return"unknown";if(t.launcher==="desktop-managed"||t.launcher==="global-cli")return t.launcher}catch{}return M(e)}function M(e){if(m()==="win32")return"unknown";try{const n=u(`ps -p ${e} -o command=`,{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).replace(/\\/g,"/");if(n.includes("/node_modules/shennian/")||n.includes("/bin/shennian")||n.includes(" shennian run-service")||n.includes(" shennian.js run-service"))return"global-cli"}catch{}return"unknown"}function ne(e=process.pid){if(m()==="win32")return Re(e);try{return u("ps -axo pid=,command=",{encoding:"utf-8",stdio:["ignore","pipe","ignore"],timeout:1e3,windowsHide:!0}).split(/\r?\n/).map(t=>{const r=t.trim().match(/^(\d+)\s+(.+)$/);if(!r)return null;const o=Number(r[1]),a=r[2];return!Number.isInteger(o)||o===e?null:xe(a)?o:null}).filter(t=>typeof t=="number")}catch{return[]}}function Ve(e=process.env,n=w,t=d.tmpdir(),r=s.join(d.homedir(),".shennian")){if(e.SHENNIAN_E2E_ISOLATED_DAEMON!=="1"||!e.SHENNIAN_HOME?.trim()||s.resolve(n)===s.resolve(r))return!1;const o=s.relative(s.resolve(t),s.resolve(n));return o!==""&&o!==".."&&!o.startsWith(`..${s.sep}`)&&!s.isAbsolute(o)||s.resolve(n)===s.resolve(e.SHENNIAN_HOME)}function Ge(e=process.env,n=w){return!Ve(e,n)}function S(e={}){let n=D(),t=n?.pid??null,r=t!==null&&A(t),o=t!==null&&!r,a=n?.adopted===!0;const l=G();if(o&&e.cleanupStale){try{i.unlinkSync(v)}catch{}n=null,t=null,r=!1,o=!1}if(!r&&Ge()){const f=ne()[0];if(f&&(t=f,r=!0,o=!1,a=!0,e.cleanupStale)){const R=Ue();je(f,R,{launcher:M(f),adopted:!0}),ee(f,M(f)),n={pid:f,instanceId:R,adopted:!0}}}return{running:r,pid:t,stale:o,remoteAccessDisabled:Te(),launcher:Be(t,r),platform:m(),shennianDir:w,pidFile:v,logFile:p,...n?.instanceId?{instanceId:n.instanceId}:{},...a?{adopted:!0}:{},...l.machineId?{machineId:l.machineId}:{},paired:!!(l.machineToken&&l.machineId),...l.serverUrl?{serverUrl:l.serverUrl}:{}}}function E(e){process.stdout.write(`${JSON.stringify(e,null,2)}
|
|
2
|
+
`)}function te(e){const n=e?.trim();if(!n)return;const t=G();t.serverUrl=n,ve(t)}function re(e){return e?.trim()||process.env.SHENNIAN_DESKTOP_SERVER_URL?.trim()||void 0}const U="com.shennian.agent",g=s.join(d.homedir(),"Library/LaunchAgents",`${U}.plist`),Je="net.shennian.client.background-service",ie=s.resolve(X,"../../native/macos-background-client/Shennian.app"),h=y("Shennian.app"),P=s.join(h,"Contents","MacOS","ShennianClientLauncher"),Ke=s.join(d.homedir(),"AppData","Roaming","Microsoft","Windows","Start Menu","Programs","Startup"),L=y("autostart.cmd"),_=y("autostart.vbs"),O=y("autostart.xml"),Xe=s.join(Ke,"ShennianAgent.vbs");function oe(e){const n=m()==="win32"?`where ${e}`:`command -v ${e}`;try{return u(n,{stdio:["ignore","pipe","pipe"],encoding:"utf-8",windowsHide:!0}).split(/\r?\n/).map(o=>o.trim()).find(Boolean)??null}catch{return null}}function qe(){const e=m()==="win32"?"npx.cmd":"npx",n=s.join(s.dirname(Y),e);return i.existsSync(n)?n:oe("npx")}function I(){return _e({nodeExec:Y,scriptPath:q,shennianCommandPath:oe("shennian"),npxPath:qe()})}function se(){try{u(`schtasks /delete /tn "${b}" /f`,{stdio:"pipe",windowsHide:!0})}catch{}}function ce(){try{i.unlinkSync(Xe)}catch{}}function Ye(){const e=process.env.USERDOMAIN?.trim(),n=process.env.COMPUTERNAME?.trim(),t=process.env.USERNAME?.trim()||d.userInfo().username;return e&&e.toUpperCase()!=="WORKGROUP"?`${e}\\${t}`:n?`${n}\\${t}`:t}function ze(e){if(m()==="win32"&&Ie(e.command)){const n=[e.command,...e.args].map(J).join(" ");return{command:process.env.ComSpec||"cmd.exe",args:["/d","/s","/c",`"${n}"`],windowsVerbatimArguments:!0}}return{command:e.command,args:e.args}}function Qe(e,n,t=process.env){return{detached:!0,stdio:["ignore",n,n],env:t,windowsHide:!0,...e.windowsVerbatimArguments?{windowsVerbatimArguments:!0}:{}}}function Ze(){const e=I();i.writeFileSync(L,Ae(e,p)),i.writeFileSync(_,De(L)),ce(),se();const n=ke({userId:Ye(),command:s.join(process.env.SystemRoot||"C:\\Windows","System32","wscript.exe"),arguments:[J(_)]});i.writeFileSync(O,n,"utf8");const t=Pe({taskName:b,xmlPath:O});try{return u(t.create,{stdio:"pipe",windowsHide:!0}),u(t.run,{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}function en(){be(b,e=>{u(e,{stdio:"pipe",windowsHide:!0})})}function ae(){const e={};for(const n of z)process.env[n]&&(e[n]=process.env[n]);if(e.HOME??=d.homedir(),e.PATH=Ee({pathValue:e.PATH,env:e}),e.USER??=d.userInfo().username,m()==="win32"){const n=process.env.TEMP||process.env.TMP||d.tmpdir(),t=d.homedir();e.USERPROFILE??=t;const r=s.win32.parse(t);e.HOMEDRIVE??=r.root.replace(/[\\/]$/,"")||process.env.HOMEDRIVE||"",e.HOMEPATH??=t.slice((e.HOMEDRIVE||"").length)||process.env.HOMEPATH||"",e.USERNAME??=process.env.USERNAME||d.userInfo().username,e.COMPUTERNAME??=process.env.COMPUTERNAME||"",e.TMPDIR??=n,e.TEMP??=n,e.TMP??=n}else e.TMPDIR??="/tmp";return e}function nn(e={}){const n=ae(),t=e.launch??I(),r=e.brandedLauncherPath===void 0?i.existsSync(P)?P:null:e.brandedLauncherPath,o=Object.entries(n).map(([f,R])=>` <key>${T(f)}</key>
|
|
3
|
+
<string>${T(R)}</string>`).join(`
|
|
4
|
+
`),a=[...r?[r,"--exec"]:[],t.command,...t.args].map(f=>` <string>${T(f)}</string>`).join(`
|
|
5
|
+
`),l=r?` <key>AssociatedBundleIdentifiers</key>
|
|
6
|
+
<array>
|
|
7
|
+
<string>${Je}</string>
|
|
8
|
+
</array>
|
|
9
|
+
`:"";return`<?xml version="1.0" encoding="UTF-8"?>
|
|
6
10
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
7
11
|
<plist version="1.0">
|
|
8
12
|
<dict>
|
|
9
13
|
<key>Label</key>
|
|
10
|
-
<string>${
|
|
11
|
-
<key>ProgramArguments</key>
|
|
14
|
+
<string>${U}</string>
|
|
15
|
+
${l} <key>ProgramArguments</key>
|
|
12
16
|
<array>
|
|
13
|
-
${
|
|
17
|
+
${a}
|
|
14
18
|
</array>
|
|
15
19
|
<key>EnvironmentVariables</key>
|
|
16
20
|
<dict>
|
|
17
|
-
${
|
|
21
|
+
${o}
|
|
18
22
|
</dict>
|
|
19
23
|
<key>RunAtLoad</key>
|
|
20
24
|
<true/>
|
|
@@ -23,12 +27,12 @@ ${t}
|
|
|
23
27
|
<key>ThrottleInterval</key>
|
|
24
28
|
<integer>5</integer>
|
|
25
29
|
<key>StandardOutPath</key>
|
|
26
|
-
<string>${
|
|
30
|
+
<string>${p}</string>
|
|
27
31
|
<key>StandardErrorPath</key>
|
|
28
|
-
<string>${
|
|
32
|
+
<string>${p}</string>
|
|
29
33
|
</dict>
|
|
30
|
-
</plist>`}const
|
|
31
|
-
`),r=[n.command,...n.args].map(
|
|
34
|
+
</plist>`}function tn(){if(!i.existsSync(ie))return console.warn(c.yellow("\u26A0 Shennian background identity bundle is missing; using the legacy launcher")),null;const e=`${h}.installing-${process.pid}`,n=`${h}.previous-${process.pid}`;try{if(i.rmSync(e,{recursive:!0,force:!0}),i.rmSync(n,{recursive:!0,force:!0}),i.cpSync(ie,e,{recursive:!0,preserveTimestamps:!0,verbatimSymlinks:!0}),i.existsSync(h)&&i.renameSync(h,n),i.renameSync(e,h),i.rmSync(n,{recursive:!0,force:!0}),i.chmodSync(P,493),ye(P,["--register-bundle",h],{stdio:"ignore",windowsHide:!0}).status!==0)throw new Error("Launch Services registration failed");return P}catch(t){try{i.rmSync(e,{recursive:!0,force:!0}),!i.existsSync(h)&&i.existsSync(n)&&i.renameSync(n,h)}catch{}return console.warn(c.yellow(`\u26A0 Unable to install the Shennian background identity; using the legacy launcher: ${t instanceof Error?t.message:String(t)}`)),null}}const N=s.join(d.homedir(),".config/systemd/user/shennian.service");function rn(){const e=ae(),n=I(),t=Object.entries(e).map(([o,a])=>`Environment=${o}=${a}`).join(`
|
|
35
|
+
`),r=[n.command,...n.args].map(Ne).join(" ");return`[Unit]
|
|
32
36
|
Description=Shennian Agent Daemon
|
|
33
37
|
After=network.target
|
|
34
38
|
|
|
@@ -37,10 +41,10 @@ ${t}
|
|
|
37
41
|
ExecStart=${r}
|
|
38
42
|
Restart=on-failure
|
|
39
43
|
RestartSec=10
|
|
40
|
-
StandardOutput=append:${
|
|
41
|
-
StandardError=append:${
|
|
44
|
+
StandardOutput=append:${p}
|
|
45
|
+
StandardError=append:${p}
|
|
42
46
|
|
|
43
47
|
[Install]
|
|
44
|
-
WantedBy=default.target`}const
|
|
48
|
+
WantedBy=default.target`}const b="ShennianAgent";function on(e){u(e,{stdio:"pipe",windowsHide:!0})}function sn(){const e=process.getuid?.();if(typeof e=="number")return e;const n=d.userInfo();return typeof n.uid=="number"?n.uid:n.username}function k(e=sn()){return`gui/${e}/${U}`}function cn(e=on){try{return e(`launchctl enable "${k()}"; launchctl unload "${g}" 2>/dev/null; launchctl load -w "${g}"`),e(`launchctl kickstart -k "${k()}"`),!0}catch{try{return e(`launchctl enable "${k()}"`),e(`launchctl load -w "${g}"`),e(`launchctl kickstart -k "${k()}"`),!0}catch{return!1}}}function an(){i.mkdirSync(w,{recursive:!0});const e={};for(const[n,t]of Object.entries(process.env))t!==void 0&&Le(n)&&(e[n]=t);i.writeFileSync(y("env.json"),JSON.stringify(e,null,2))}function ue(e={}){i.mkdirSync(w,{recursive:!0});const n=S({cleanupStale:!0});if(n.pid!==null&&n.running&&!j(n)){e.quiet||console.log(c.green(`\u2713 Background service already running (PID ${n.pid})`));return}de(n);const t=i.openSync(p,"a"),r=ze(I()),o=he(r.command,r.args,Qe(r,t));o.unref(),i.closeSync(t),Fe(o.pid),e.quiet||(console.log(c.green(`\u2713 Background service started (PID ${o.pid})`)),console.log(c.gray(` Logs: ${p}`)))}function j(e,n=D(),t=K()){return e.pid===null||!e.running?!1:e.adopted===!0||n?.version!==t}function W(e=m()){switch(e){case"darwin":return i.existsSync(g)&&i.existsSync(P);case"linux":return i.existsSync(N);case"win32":return i.existsSync(L)&&i.existsSync(_)&&i.existsSync(O)}}function un(e,n,t,r=D(),o=K()){return!n.api?.trim()&&e.pid!==null&&e.running&&!e.stale&&!e.remoteAccessDisabled&&t&&!j(e,r,o)}function de(e=S({cleanupStale:!0})){if(!(!j(e)||e.pid===null))try{process.kill(e.pid,"SIGTERM"),Q(e.pid,5e3)||(process.kill(e.pid,"SIGKILL"),Q(e.pid,2e3));try{D()?.pid===e.pid&&i.unlinkSync(v)}catch{}}catch{}}function le(){i.mkdirSync(w,{recursive:!0});const e=m();switch(I().mode==="direct"&&H(q)&&console.warn(c.yellow("\u26A0 Warning: Current CLI path is temporary (npx). Auto-start may not work after reboot.\n Run `npm install -g shennian@latest` for reliable auto-start.")),e){case"darwin":{const t=s.dirname(g);i.mkdirSync(t,{recursive:!0});const r=tn();return i.writeFileSync(g,nn({brandedLauncherPath:r})),cn()}case"linux":{const t=s.dirname(N);i.mkdirSync(t,{recursive:!0}),i.writeFileSync(N,rn());try{u("systemctl --user daemon-reload && systemctl --user enable shennian",{stdio:"pipe",windowsHide:!0})}catch{return!1}try{u(`loginctl enable-linger ${d.userInfo().username}`,{stdio:"pipe",windowsHide:!0})}catch{}try{return u("systemctl --user restart shennian",{stdio:"pipe",windowsHide:!0}),!0}catch{return!1}}case"win32":return Ze()}}function dn(){const n=S({cleanupStale:!0}).pid;if(n===null)return{};if(!A(n)){try{i.unlinkSync(v)}catch{}return{stalePid:n}}try{return process.kill(n,"SIGTERM"),{stoppedPid:n}}catch(t){return{error:t instanceof Error?t.message:String(t)}}}async function pe(e=5e3){const n=dn();if(!n.stoppedPid)return n;if(!await B(n.stoppedPid,e))try{process.kill(n.stoppedPid,"SIGKILL"),await B(n.stoppedPid,2e3)}catch(r){return{...n,error:r instanceof Error?r.message:String(r)}}try{i.unlinkSync(v)}catch{}We();for(const r of ne())if(r!==n.stoppedPid)try{process.kill(r,"SIGTERM"),await B(r,2e3)}catch{}return n}function ln(e={}){te(re(e.api)),$e(),de(),le()||ue({quiet:e.json}),e.json?E($(()=>S({cleanupStale:!0}))):console.log(c.green("\u2713 Background service started"))}async function pn(e={}){const n=He(),t=Me(),r=await pe(),o=S({cleanupStale:!0}),a=r.error??n.autoStartError??t.error;if(e.json){E(a?{...o,error:a}:o);return}a?console.error(c.red(`\u2717 Failed to stop completely: ${a}`)):console.log(c.green("\u2713 Background service stopped"))}function me(e){const n=S({cleanupStale:!0});if(un(n,e,W())){e.json?E(n):console.log(c.green(`\u2713 Background service already running (PID ${n.pid})`));return}an(),ln(e)}async function F(e={}){await pn(e)}async function B(e,n=5e3){const t=Date.now();for(;Date.now()-t<n;){if(!A(e))return!0;await new Promise(r=>setTimeout(r,100))}return!A(e)}async function mn(e={}){const n=S({cleanupStale:!0});if(n.remoteAccessDisabled){e.json?E({...n,error:"remote_access_disabled_use_shennian_start"}):console.error(c.yellow("Remote access is paused. Run `shennian start` on this computer to resume."));return}te(re(e.api));const t=m();t==="win32"&&en();const r=await pe();if(r.error){e.json?E({...S(),error:r.error}):console.error(c.red(`\u2717 Failed to stop: ${r.error}`));return}if(r.stoppedPid!==void 0?e.json||console.log(c.green(`\u2713 Background service stopped (PID ${r.stoppedPid})`)):r.stalePid!==void 0?e.json||console.log(c.yellow(`\u26A0 Service process no longer exists, cleaned up stale PID ${r.stalePid}`)):e.json||console.log(c.gray("\u25CF Background service not running, starting it now")),(t==="linux"||t==="win32")&&le()){e.json&&E($(()=>S({cleanupStale:!0})));return}ue({quiet:e.json}),e.json&&E($(()=>S({cleanupStale:!0})))}function fe(e={}){const n=S({cleanupStale:!0});if(e.json){E(n);return}if(n.pid===null){console.log(c.gray("\u25CF Background service not running"));return}n.running?(console.log(c.green(`\u25CF Background service running (PID ${n.pid})`)),console.log(c.gray(` Logs: ${p}`))):console.log(c.yellow(`\u25CF Background service stopped (PID ${n.pid} is stale)`))}function Se(e){if(!i.existsSync(p)){console.log(c.gray("No logs yet"));return}try{const n=u(d.platform()==="win32"?`powershell Get-Content -Tail ${e.lines} "${p}"`:`tail -n ${e.lines} "${p}"`,{encoding:"utf-8",windowsHide:!0});process.stdout.write(n)}catch{const n=i.readFileSync(p,"utf-8").split(`
|
|
45
49
|
`).slice(-e.lines);console.log(n.join(`
|
|
46
|
-
`))}}async function
|
|
50
|
+
`))}}async function fn(){switch(await F(),m()){case"darwin":{if(i.existsSync(g)){try{u(`launchctl unload -w "${g}"`,{stdio:"pipe",windowsHide:!0})}catch{}i.unlinkSync(g)}i.rmSync(h,{recursive:!0,force:!0}),console.log(c.green("\u2713 Auto-start uninstalled (launchd)"));break}case"linux":{try{u("systemctl --user disable --now shennian",{stdio:"pipe",windowsHide:!0})}catch{}if(i.existsSync(N)){i.unlinkSync(N);try{u("systemctl --user daemon-reload",{stdio:"pipe",windowsHide:!0})}catch{}}console.log(c.green("\u2713 Auto-start uninstalled (systemd)"));break}case"win32":{se();try{i.unlinkSync(L)}catch{}try{i.unlinkSync(_)}catch{}try{i.unlinkSync(O)}catch{}ce(),console.log(c.green("\u2713 Auto-start uninstalled (Task Scheduler)"));break}}}function Rn(e){e.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>me(r)),e.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(r=>F(r)),e.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(r=>fe(r)),e.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(r=>Se({lines:parseInt(r.lines,10)}));const n=e.command("daemon",{hidden:!0}).description("Deprecated: use top-level start/stop/status/logs"),t=(r,o)=>{o||console.error(c.yellow(`\u26A0 Deprecated command. Use \`shennian ${r}\` instead.`))};n.command("start").description("Start the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>{t("start",r.json),me(r)}),n.command("stop").description("Stop the background service").option("--json","Print machine-readable status JSON").action(async r=>{t("stop",r.json),await F(r)}),n.command("restart").description("Restart the background service").option("--json","Print machine-readable status JSON").option("--api <url>","Server URL override").action(r=>{t("stop && shennian start",r.json),mn(r)}),n.command("status").description("Show background service status").option("--json","Print machine-readable status JSON").action(r=>{t("status",r.json),fe(r)}),n.command("logs").description("Show recent logs").option("-n, --lines <n>","Number of lines","50").action(r=>{t("logs"),Se({lines:parseInt(r.lines,10)})}),n.command("uninstall").description("Uninstall auto-start service").action(fn)}export{Qe as buildDaemonSpawnOptions,nn as buildMacLaunchdPlist,rn as buildSystemdUnit,_n as buildWindowsLauncherCommand,On as buildWindowsScheduledTaskCommands,Tn as buildWindowsScheduledTaskSuspendCommands,$n as buildWindowsScheduledTaskXml,Cn as buildWindowsStartupVbs,un as canReuseRunningDaemonForStart,ae as captureEnvForService,We as clearDaemonLauncher,bn as clearDaemonPidIfOwner,$e as clearRemoteAccessDisabled,Ue as createDaemonInstanceId,ne as findRunningDaemonProcessIds,Z as getCurrentProcessDaemonLauncher,S as getDaemonStatus,k as getLaunchdServiceTarget,le as installService,W as isAutoStartServicePresent,H as isEphemeralCliPath,Ve as isIsolatedDaemonE2eInstance,Te as isRemoteAccessDisabled,Le as isSafeSnapshotEnvKey,Un as isShennianRunServiceCommand,He as prepareRemoteAccessPause,Fe as recordStartedDaemon,Rn as registerDaemonCommand,cn as reloadLaunchdAgent,_e as resolveServiceLaunchSpec,an as saveEnvSnapshot,Ge as shouldDiscoverGlobalDaemonProcesses,j as shouldReplaceRunningDaemon,ue as startDaemonProcess,Me as stopPreparedRemoteAccessService,Hn as suspendWindowsScheduledTask,ee as writeDaemonLauncher,je as writeDaemonPid};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import u from"node:crypto";import{spawn as f}from"node:child_process";import{HttpDeviceAuthorizationClient as p}from"../room/device-authorization-client.js";import{getDaemonInstallationId as A}from"../personal-sync/identity.js";import{hashActionPayload as g,hashPendingDeviceSecret as P}from"./pair-authorization.js";const L=3e3;class a extends Error{code;constructor(r,t){super(t),this.code=r,this.name="BrowserPairError"}}async function O(e){const r=new p(e.serverUrl),t=u.randomBytes(32).toString("base64url"),n=A(),c={action:"pair_machine",agentList:[...e.agentList].sort(),daemonInstallationId:n,machineName:e.machineName,machineOs:e.machineOs},d=g(c),o=await r.create({deviceSecretHash:P(t),daemonInstallationId:n,machineName:e.machineName,machineOs:e.machineOs,agentList:e.agentList,actionType:"machine.pair",actionSummary:"Pair this machine with your Shennian account",actionPayloadHash:d,returnTo:"/spaces"}),m=y(o.publicLoginUrl,e.serverUrl);e.emit?.({type:"pair.browser.created",intentId:o.loginIntentId,url:m,expiresAt:o.expiresAt}),await(e.openUrl??_)(m).catch(()=>!1);const I=new Date(o.expiresAt).getTime(),h=e.pollIntervalMs??L;let l=!1;for(;Date.now()<I;){if(e.signal?.aborted)throw await r.cancel({loginIntentId:o.loginIntentId,deviceSecret:t}).catch(()=>{}),new a("PAIR_CANCELLED","Pairing was cancelled");let s;try{s=await r.getStatus({loginIntentId:o.loginIntentId,deviceSecret:t})}catch{await w(h,e.signal);continue}if(s.actionPayloadHash!==d)throw new a("PAIR_PAYLOAD_MISMATCH","Authorization request changed unexpectedly");if(s.status==="denied")throw new a("PAIR_DENIED","Pairing request was denied");if(s.status==="expired")throw new a("PAIR_EXPIRED","Pairing request expired");if(s.status==="claimed")throw new a("PAIR_ALREADY_CLAIMED","Pairing credentials were already claimed");if(s.status==="approved"){const i=await r.claim({loginIntentId:o.loginIntentId,deviceSecret:t});if(i.actionPayloadHash!==d||!i.machineId||!i.machineToken||!i.accountNamespaceId)throw new a("PAIR_INVALID_CLAIM","Authorization did not return machine credentials");return e.emit?.({type:"pair.claimed"}),{machineId:i.machineId,machineToken:i.machineToken,accountNamespaceId:i.accountNamespaceId,machineName:e.machineName,publicLoginUrl:m}}l||(l=!0,e.emit?.({type:"pair.waiting"})),await w(h,e.signal)}throw new a("PAIR_TIMEOUT","Timed out waiting for browser authorization")}function S(e){if(e.browser&&e.token)throw new a("PAIR_MODE_CONFLICT","Choose either --browser or --token, not both");return e.browser?"browser":e.token||e.json||!e.stdinIsTty||!e.stdoutIsTty?"token":"prompt"}function U(e){return e.trim()==="2"?"token":"browser"}async function _(e){if(process.env.SSH_CONNECTION||process.env.SSH_TTY)return!1;const{command:r,args:t}=T(process.platform,e);return new Promise(n=>{const c=f(r,t,{detached:!0,stdio:"ignore",windowsHide:!0});c.once("error",()=>n(!1)),c.once("spawn",()=>{c.unref(),n(!0)})})}function T(e,r){return e==="darwin"?{command:"open",args:[r]}:e==="win32"?{command:"explorer.exe",args:[r]}:{command:"xdg-open",args:[r]}}function y(e,r){let t,n;try{t=new URL(e),n=new URL(r)}catch{throw new a("PAIR_INVALID_AUTHORIZATION_URL","Server returned an invalid authorization URL")}if(!["http:","https:"].includes(t.protocol)||t.hostname!==n.hostname||t.username||t.password||t.search||t.hash||!/^\/authorize\/[A-Za-z0-9_-]{8,128}$/.test(t.pathname))throw new a("PAIR_INVALID_AUTHORIZATION_URL","Server returned an unsafe authorization URL");return t.toString()}function w(e,r){return new Promise(t=>{if(r?.aborted)return t();const n=setTimeout(t,e);r?.addEventListener("abort",()=>{clearTimeout(n),t()},{once:!0})})}export{a as BrowserPairError,T as browserOpenCommand,y as normalizePairAuthorizationUrl,_ as openExternalUrl,U as parsePairModeChoice,S as resolvePairMode,O as runBrowserPairFlow};
|
|
@@ -2,6 +2,7 @@ export type DeviceAuthorizationStatus = 'waiting_user' | 'approved' | 'denied' |
|
|
|
2
2
|
export interface DeviceAuthorizationClient {
|
|
3
3
|
create(input: {
|
|
4
4
|
deviceSecretHash: string;
|
|
5
|
+
daemonInstallationId: string;
|
|
5
6
|
machineName: string;
|
|
6
7
|
machineOs: string;
|
|
7
8
|
agentList: string[];
|
|
@@ -49,6 +50,7 @@ export declare class HttpDeviceAuthorizationClient implements DeviceAuthorizatio
|
|
|
49
50
|
constructor(serverUrl: string, fetchImpl?: FetchLike);
|
|
50
51
|
create(input: {
|
|
51
52
|
deviceSecretHash: string;
|
|
53
|
+
daemonInstallationId: string;
|
|
52
54
|
machineName: string;
|
|
53
55
|
machineOs: string;
|
|
54
56
|
agentList: string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ManagedAgentEnforcement, ManagedAgentPermissionPolicy, AgentType, RoomActivationMode } from '@shennian/wire';
|
|
2
|
-
export declare const MANAGED_ROOM_POLICY_VERSION = "managed-room-surface-
|
|
2
|
+
export declare const MANAGED_ROOM_POLICY_VERSION = "managed-room-surface-v6";
|
|
3
3
|
export type ManagedRoomPromptInput = {
|
|
4
4
|
agent: {
|
|
5
5
|
displayName: string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import $ from"node:crypto";import h from"node:path";const v="managed-room-surface-
|
|
1
|
+
import $ from"node:crypto";import h from"node:path";const v="managed-room-surface-v6",O=["shennian room status","shennian room read [--before <sequence> | --after <sequence>] [--limit <1-50>]","shennian room send [--text <\u5185\u5BB9>] [--file <\u672C\u5730\u6587\u4EF6\u8DEF\u5F84> ...]","shennian room attachment get <attachment-id>","shennian room pause --reason <\u7B80\u77ED\u539F\u56E0>"],x=["shennian_room_status","shennian_room_read","shennian_room_send","shennian_room_attachment_get","shennian_room_pause"];function I(e){const o=m(e.agent.displayName,191,"\u5F53\u524D\u667A\u80FD\u4F53"),n=m(e.agent.description??"",1e3,"\u672A\u8BBE\u7F6E")||"\u672A\u8BBE\u7F6E",t=m(e.room.name,191,"\u5F53\u524D\u7FA4\u804A"),r=(e.room.members??[]).slice(0,100).map(s=>{const g=m(s.displayName,191,"\u7FA4\u6210\u5458"),P=s.principalType==="agent"?"\u667A\u80FD\u4F53":"\u771F\u4EBA",y=s.principalType==="agent"&&s.description?`\uFF5C${m(s.description,1e3,"")}`:"",w=s.principalType==="agent"&&s.ownerDisplayName?`\uFF5C\u6240\u5C5E\u6210\u5458\uFF1A${m(s.ownerDisplayName,191,"")}`:"";return`- ${g}\uFF5C${P}${y}${w}`}),c=[`[\u667A\u80FD\u4F53\u8EAB\u4EFD]
|
|
2
2
|
\u540D\u79F0\uFF1A${o}
|
|
3
3
|
\u516C\u5F00\u804C\u8D23\uFF1A${n}`,`[\u5F53\u524D\u7FA4\u804A]
|
|
4
4
|
\u7FA4\u804A\uFF1A${t}
|
|
@@ -18,6 +18,7 @@ ${r.length?r.join(`
|
|
|
18
18
|
${p?`\u53EA\u5728\u5185\u90E8\u5BF9\u8BDD\u4E2D\u751F\u6210\u6587\u5B57\u4E0D\u7B49\u4E8E\u5DF2\u7ECF\u56DE\u590D\u7FA4\u804A\uFF0C\u5B8C\u6210\u7FA4\u804A\u53D1\u9001\u5FC5\u987B\u8C03\u7528\u5F53\u524D\u7FA4\u804A\u5DE5\u5177\u3002
|
|
19
19
|
\u672C\u5730\u9644\u4EF6\u4E0A\u4F20\u5F53\u524D\u4E0D\u53EF\u7528\uFF1B\u9700\u8981\u53D1\u9001\u957F\u6587\u6863\u65F6\uFF0C\u5148\u53D1\u9001\u7B80\u77ED\u6458\u8981\u5E76\u8BF4\u660E\u6B64\u9650\u5236\u3002`:`\u53EA\u5728\u5185\u90E8\u5BF9\u8BDD\u4E2D\u751F\u6210\u6587\u5B57\u4E0D\u7B49\u4E8E\u5DF2\u7ECF\u56DE\u590D\u7FA4\u804A\uFF0C\u5B8C\u6210\u7FA4\u804A\u53D1\u9001\u5FC5\u987B\u6267\u884C Shennian CLI\u3002
|
|
20
20
|
\u957F\u6587\u6863\u4F18\u5148\u4F5C\u4E3A\u9644\u4EF6\u53D1\u9001\uFF0C\u5E76\u9644\u7B80\u77ED\u7EAF\u6587\u672C\u8BF4\u660E\u3002`}
|
|
21
|
+
\u6536\u5230\u9700\u8981\u5904\u7406\u7684\u4EFB\u52A1\u540E\uFF0C\u5148\u5728\u7FA4\u91CC\u7B80\u77ED\u8BF4\u660E\u5DF2\u6536\u5230\u548C\u51C6\u5907\u600E\u4E48\u505A\uFF0C\u518D\u5F00\u59CB\u6267\u884C\uFF1B\u8017\u65F6\u8F83\u957F\u65F6\u9002\u5F53\u540C\u6B65\u8FDB\u5C55\uFF0C\u5B8C\u6210\u540E\u56DE\u590D\u7ED3\u679C\u3002\u7B80\u5355\u95EE\u9898\u53EF\u76F4\u63A5\u56DE\u7B54\u3002
|
|
21
22
|
Room \u6B63\u6587\u5F53\u524D\u6309\u7EAF\u6587\u672C\u663E\u793A\uFF1B\u53D1\u9001\u65F6\u4F7F\u7528\u77ED\u6BB5\u843D\u548C\u81EA\u7136\u6362\u884C\uFF0C\u4E0D\u8981\u4F7F\u7528 Markdown \u6807\u8BB0\u3002`,l,a?`[\u4F1A\u8BDD\u6A21\u5F0F]
|
|
22
23
|
${a}`:"",i?`[\u667A\u80FD\u4F53\u79C1\u6709\u7CFB\u7EDF\u63D0\u793A\u8BCD]
|
|
23
24
|
${i}`:"",c,`[\u7FA4\u6D88\u606F\u683C\u5F0F]
|
|
@@ -54,6 +54,7 @@ export declare function fetchLatestVersion(): Promise<string>;
|
|
|
54
54
|
* 'major' — major differs
|
|
55
55
|
*/
|
|
56
56
|
export declare function compareVersions(current: string, latest: string): 'none' | 'patch' | 'minor' | 'major';
|
|
57
|
+
export declare function resolveNpmGlobalPrefixFromPackageJson(packageJsonPath: string, platform?: NodeJS.Platform): string | null;
|
|
57
58
|
export declare function readUpgradeAttempt(): UpgradeAttempt | null;
|
|
58
59
|
export declare function writeUpgradeAttempt(attempt: UpgradeAttempt): void;
|
|
59
60
|
export declare function clearUpgradeAttempt(): void;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
1
|
+
import s from"node:fs";import c from"node:path";import{execSync as U,execFile as T}from"node:child_process";import{promisify as P}from"node:util";import{fileURLToPath as L}from"node:url";import{getShennianDir as _,resolveShennianPath as d}from"../config/index.js";const f=P(T),m=d("upgrade-attempt.json"),G=3,I="https://registry.npmjs.org",H=10*6e4,$=[5*6e4,30*6e4,120*6e4,360*6e4];function y(){try{const e=g();if(e)return JSON.parse(s.readFileSync(e,"utf-8")).version}catch{}return"0.0.0"}function g(e=L(import.meta.url)){let r=c.dirname(e);for(let n=0;n<6;n++){const t=c.join(r,"package.json");if(s.existsSync(t)&&JSON.parse(s.readFileSync(t,"utf-8")).name==="shennian")return t;r=c.dirname(r)}return null}async function B(){const e=await fetch("https://registry.npmjs.org/shennian/latest",{headers:{Accept:"application/json"},signal:AbortSignal.timeout(1e4)});if(!e.ok)throw new Error(`npm registry returned ${e.status}`);return(await e.json()).version}function Y(e,r){const n=p=>p.replace(/^v/,"").split(".").map(Number),[t,i,o]=n(e),[a,u,l]=n(r);return a>t?"major":a===t&&u>i?"minor":a===t&&u===i&&l>o?"patch":"none"}function z(){return U("npm root -g",{encoding:"utf-8",stdio:"pipe",windowsHide:!0}).trim()}function K(e,r=process.platform){const n=r==="win32"?c.win32:c.posix,t=n.dirname(e),i=n.dirname(t);if(n.basename(i)!=="node_modules")return null;const o=n.dirname(i);return n.basename(o)==="lib"?n.dirname(o):o}function N(){const e=g();return e?K(e):null}function X(){const e=g();return e?c.join(c.dirname(e),"dist","bin","shennian.js"):c.join(z(),"shennian","dist","bin","shennian.js")}function Z(){try{return JSON.parse(s.readFileSync(m,"utf-8"))}catch{return null}}function h(e){s.mkdirSync(_(),{recursive:!0}),s.writeFileSync(m,JSON.stringify(e,null,2))}function k(){try{s.unlinkSync(m)}catch{}}function R(){return d("upgrade-failures.json")}function q(){return d("upgrade.lock")}function j(e=q(),r={}){const n=r.now??Date.now(),t=r.pid??process.pid,i=r.isProcessAlive??(l=>{try{return process.kill(l,0),!0}catch{return!1}});s.mkdirSync(c.dirname(e),{recursive:!0});const o=()=>s.openSync(e,"wx",384);let a;try{a=o()}catch(l){if(l.code!=="EEXIST")throw l;let p=!1;try{const v=JSON.parse(s.readFileSync(e,"utf-8")),E=Number(v.pid),F=Number(v.createdAt);p=!Number.isInteger(E)||!Number.isFinite(F)||n-F>H||!i(E)}catch{p=!0}if(!p)throw new Error("Another Shennian upgrade is already running");s.rmSync(e,{force:!0}),a=o()}s.writeFileSync(a,JSON.stringify({pid:t,createdAt:n})),s.closeSync(a);let u=!1;return{release(){if(!u){u=!0;try{s.unlinkSync(e)}catch{}}}}}function w(e=R()){try{const r=JSON.parse(s.readFileSync(e,"utf-8"));return!r||typeof r!="object"||!r.versions?{versions:{}}:{versions:r.versions}}catch{return{versions:{}}}}function C(e){s.mkdirSync(_(),{recursive:!0}),s.writeFileSync(R(),JSON.stringify(e,null,2))}function Q(e){return $[Math.min(Math.max(e-1,0),$.length-1)]}function ie(e,r=Date.now(),n=w()){const t=n.versions[e];return!!(t&&t.nextRetryAt>r)}function se(e,r,n=Date.now()){const t=w(),i=t.versions[e],o=(i?.failureCount??0)+1,a={version:e,failureCount:o,firstFailedAt:i?.firstFailedAt??n,lastFailedAt:n,nextRetryAt:n+Q(o),error:r};return t.versions[e]=a,C(t),a}function S(e){const r=w();r.versions[e]&&(delete r.versions[e],C(r))}async function ce(){const e=Z();if(!e)return!1;if(Date.now()-e.attemptAt>600*1e3)return k(),!1;if(e.attemptCount++,e.attemptCount>=G){console.error(`[upgrade] New version crashed ${e.attemptCount} times, rolling back to ${e.from}...`);let n;try{n=j()}catch(t){return console.error(`[upgrade] Rollback deferred: ${t instanceof Error?t.message:String(t)}`),!1}try{return await J(e.from),k(),console.error(`[upgrade] Rolled back to ${e.from}. Restarting...`),!0}catch(t){return console.error(`[upgrade] Rollback failed: ${t instanceof Error?t.message:String(t)}`),k(),!1}finally{n.release()}}return h(e),!1}async function le(e,r,n={}){let t;try{t=j()}catch(i){return{ok:!1,error:i instanceof Error?i.message:String(i)}}try{return await W(e,r,n)}finally{t.release()}}async function W(e,r,n={}){const t=n.currentVersion??y(),i=y();if(t===e)return S(e),{ok:!1,error:`Already on version ${e}`};r({step:"checking"});try{U("npm --version",{stdio:"pipe",windowsHide:!0})}catch{return{ok:!1,error:"npm is not available in PATH"}}if(i===e){r({step:"verifying",version:e});try{await b(e)}catch(o){return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}`}}return h({from:t,to:e,attemptCount:0,attemptAt:Date.now()}),S(e),r({step:"restarting",from:t,to:e}),{ok:!0,from:t,to:e}}r({step:"backing-up"}),r({step:"installing",version:e});try{await D(e)}catch(o){const a=await O(t);return{ok:!1,error:`npm install failed: ${o instanceof Error?o.message:String(o)}${a.ok?"":`; rollback failed: ${a.error}`}`,rolledBack:a.ok}}r({step:"verifying",version:e});try{await b(e)}catch(o){const a=await O(t);return{ok:!1,error:`Smoke test failed: ${o instanceof Error?o.message:String(o)}${a.ok?"":`; rollback failed: ${a.error}`}`,rolledBack:a.ok}}return h({from:t,to:e,attemptCount:0,attemptAt:Date.now()}),S(e),r({step:"restarting",from:t,to:e}),{ok:!0,from:t,to:e}}function M(e){if(!/^[0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(e))throw new Error(`Invalid npm version: ${e}`)}function x(){return process.platform==="win32"?"npm.cmd":"npm"}function V(e,r){return{timeout:r,windowsHide:!0,shell:e==="win32"}}function A(e){return V(process.platform,e)}async function D(e){M(e);const r=N(),n=["install","-g",`shennian@${e}`,...r?["--prefix",r]:[]];try{await f(x(),n,A(12e4))}catch(t){const i=t instanceof Error?t.message:String(t);try{await f(x(),[...n,"--registry",I],{...A(12e4)})}catch(o){const a=o instanceof Error?o.message:String(o);throw new Error(`${i}
|
|
2
2
|
--- npmjs fallback ---
|
|
3
|
-
${
|
|
3
|
+
${a}`)}}}async function b(e){M(e);const r=X(),{stdout:n}=await f(process.execPath,[r,"--version"],{timeout:1e4,windowsHide:!0});if(n.trim()!==e)throw new Error(`Version verification failed: expected ${e}, got ${n.trim()||"empty output"}`);const t=N();await f(x(),["ls","-g",`shennian@${e}`,"--omit=dev","--depth=0",...t?["--prefix",t]:[]],{...A(3e4)})}async function J(e,r={}){await(r.install??D)(e),await(r.verify??b)(e)}async function O(e){try{return await J(e),{ok:!0}}catch(r){return{ok:!1,error:r instanceof Error?r.message:String(r)}}}async function ue(e){const r=e??y(),n=await B(),t=Y(r,n);return t==="none"?{hasUpdate:!1}:{hasUpdate:!0,current:r,latest:n,changeType:t}}export{j as acquireUpgradeLock,ue as checkForUpdate,k as clearUpgradeAttempt,S as clearUpgradeFailure,Y as compareVersions,B as fetchLatestVersion,g as findPackageJson,y as getCurrentVersion,Q as getUpgradeRetryDelayMs,ce as handleStartupCrashCheck,D as installShennianVersion,ie as isUpgradeVersionInCooldown,V as npmExecOptionsForPlatform,le as performUpgrade,Z as readUpgradeAttempt,w as readUpgradeFailures,se as recordUpgradeFailure,K as resolveNpmGlobalPrefixFromPackageJson,J as rollbackToExactVersion,b as verifyInstalledVersion,h as writeUpgradeAttempt};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shennian",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Shennian — AI Agent Control Plane CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"typescript": "^5.9.3"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
|
-
"build": "tsc && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\"",
|
|
59
|
-
"build:publish": "pnpm --filter @shennian/wire build:publish && node -e \"const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.rmSync('.tsbuildinfo.publish', { force: true })\" && tsc -p tsconfig.publish.json && node scripts/minify-publish-js.mjs && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\" && node scripts/check-publish-artifact.mjs",
|
|
58
|
+
"build": "tsc && node scripts/copy-macos-background-client.mjs && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\"",
|
|
59
|
+
"build:publish": "pnpm --filter @shennian/wire build:publish && node -e \"const fs=require('node:fs'); fs.rmSync('dist', { recursive: true, force: true }); fs.rmSync('.tsbuildinfo.publish', { force: true })\" && tsc -p tsconfig.publish.json && node scripts/copy-macos-background-client.mjs && node scripts/minify-publish-js.mjs && node -e \"require('node:fs').chmodSync('dist/bin/shennian.js', 0o755)\" && node scripts/check-publish-artifact.mjs",
|
|
60
60
|
"test:security:codex": "tsx scripts/verify-managed-codex-sandbox.ts",
|
|
61
61
|
"test:security:codex-tools": "tsx scripts/verify-managed-codex-dynamic-tools.ts",
|
|
62
62
|
"dev": "tsc --watch"
|