@nowcrew/daemon 0.6.97-beta.14 → 0.6.97-beta.16

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.
@@ -4,6 +4,7 @@ import { buildServiceSpec, serviceStatus, windowsCommandArg, } from "./computer-
4
4
  import { daemonGlobalInstallation } from "./daemon-installation.js";
5
5
  import { inspectLegacyServiceInstallationDetails } from "./legacy-service-installation.js";
6
6
  import { powershellCommandArgs } from "./powershell-command.js";
7
+ import { windowsTaskPrincipalFields, windowsTaskPrincipalMatches, windowsTaskPrincipalScript, } from "./windows-task-principal.js";
7
8
  function encoded(value) {
8
9
  return Buffer.from(value, "utf16le").toString("base64");
9
10
  }
@@ -143,8 +144,9 @@ async function discoverWindows(input, identity) {
143
144
  "$n=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[0]));",
144
145
  "$tasks=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});",
145
146
  "if($tasks.Count -ne 1){[pscustomobject]@{count=$tasks.Count}|ConvertTo-Json -Compress;exit 0};",
146
- "$task=$tasks[0];$actions=@($task.Actions);$me=[Security.Principal.WindowsIdentity]::GetCurrent().Name;",
147
- "[pscustomobject]@{count=1;state=[int]$task.State;actionCount=$actions.Count;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};principalMatches=([String]::Equals($task.Principal.UserId,$me,[StringComparison]::OrdinalIgnoreCase)-and [int]$task.Principal.LogonType -eq 3 -and [int]$task.Principal.RunLevel -eq 0)}|ConvertTo-Json -Compress;",
147
+ "$task=$tasks[0];$actions=@($task.Actions);",
148
+ windowsTaskPrincipalScript,
149
+ `[pscustomobject]@{count=1;state=[int]$task.State;actionCount=$actions.Count;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};${windowsTaskPrincipalFields}}|ConvertTo-Json -Compress;`,
148
150
  ].join("");
149
151
  const result = await input.runner("powershell.exe", powershellCommandArgs(script, [encoded(identity.id)]));
150
152
  if (result.exitCode !== 0) {
@@ -164,7 +166,7 @@ async function discoverWindows(input, identity) {
164
166
  : null;
165
167
  if (definition.count !== 1
166
168
  || definition.actionCount !== 1
167
- || definition.principalMatches !== true
169
+ || !windowsTaskPrincipalMatches(definition)
168
170
  || !win32.isAbsolute(definition.execute ?? "")
169
171
  || match === null
170
172
  || match[2] !== input.desired.profile
File without changes
@@ -6,6 +6,7 @@ import { promisify } from "node:util";
6
6
  import { dirname, resolve } from "node:path";
7
7
  import { normalizeDaemonNpmRegistry } from "./npm-registry.js";
8
8
  import { daemonRegistryCandidates } from "./daemon-registry.js";
9
+ import { windowsTaskPrincipalFields, windowsTaskPrincipalMatches, windowsTaskPrincipalScript, } from "./windows-task-principal.js";
9
10
  import { npmInvocation } from "./npm-command.js";
10
11
  import { powershellCommandArgs } from "./powershell-command.js";
11
12
  const execFileAsync = promisify(execFile);
@@ -196,8 +197,9 @@ async function windowsTaskDefinitionMatches(spec, runner) {
196
197
  "$n=[Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($args[0]));",
197
198
  "$tasks=@(Get-ScheduledTask -ErrorAction Stop|Where-Object{$_.TaskPath -eq '\\' -and $_.TaskName -ceq $n});",
198
199
  "if($tasks.Count -ne 1){[pscustomobject]@{count=$tasks.Count}|ConvertTo-Json -Compress;exit 0};",
199
- "$task=$tasks[0];$actions=@($task.Actions);$me=[Security.Principal.WindowsIdentity]::GetCurrent().Name;",
200
- "[pscustomobject]@{count=1;actionCount=$actions.Count;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};principalMatches=([String]::Equals($task.Principal.UserId,$me,[StringComparison]::OrdinalIgnoreCase)-and [int]$task.Principal.LogonType -eq 3 -and [int]$task.Principal.RunLevel -eq 0)}|ConvertTo-Json -Compress;",
200
+ "$task=$tasks[0];$actions=@($task.Actions);",
201
+ windowsTaskPrincipalScript,
202
+ `[pscustomobject]@{count=1;actionCount=$actions.Count;execute=if($actions.Count -eq 1){$actions[0].Execute}else{$null};arguments=if($actions.Count -eq 1){$actions[0].Arguments}else{$null};${windowsTaskPrincipalFields}}|ConvertTo-Json -Compress;`,
201
203
  ].join("");
202
204
  const result = await runner("powershell.exe", powershellCommandArgs(script, [encodedName]));
203
205
  if (result.exitCode !== 0) {
@@ -213,7 +215,7 @@ async function windowsTaskDefinitionMatches(spec, runner) {
213
215
  const expectedArguments = spec.daemonCommand.slice(1).map(windowsCommandArg).join(" ");
214
216
  return definition.count === 1
215
217
  && definition.actionCount === 1
216
- && definition.principalMatches === true
218
+ && windowsTaskPrincipalMatches(definition)
217
219
  && sameWindowsPath(definition.execute, spec.daemonCommand[0])
218
220
  && definition.arguments === expectedArguments;
219
221
  }
package/dist/main.js CHANGED
File without changes
@@ -0,0 +1,26 @@
1
+ /** Read only: resolve the task's account with Windows, without guessing or stripping its domain. */
2
+ export const windowsTaskPrincipalScript = [
3
+ "$currentUserSid=[Security.Principal.WindowsIdentity]::GetCurrent().User.Value;",
4
+ "$principalSid=$null;",
5
+ "try{",
6
+ "$account=[string]$task.Principal.UserId;",
7
+ "if($account -match '^S-\\d-'){",
8
+ "$principalSid=([Security.Principal.SecurityIdentifier]::new($account)).Value;",
9
+ "}else{",
10
+ "$principalSid=([Security.Principal.NTAccount]::new($account)).Translate([Security.Principal.SecurityIdentifier]).Value;",
11
+ "}",
12
+ "}catch{$principalSid=$null};",
13
+ ].join("");
14
+ export const windowsTaskPrincipalFields = [
15
+ "currentUserSid=$currentUserSid;",
16
+ "principalSid=$principalSid;",
17
+ "logonType=[int]$task.Principal.LogonType;",
18
+ "runLevel=[int]$task.Principal.RunLevel;",
19
+ ].join("");
20
+ export function windowsTaskPrincipalMatches(principal) {
21
+ return typeof principal.currentUserSid === "string"
22
+ && /^S-1-(?:\d+-)*\d+$/.test(principal.currentUserSid)
23
+ && principal.principalSid === principal.currentUserSid
24
+ && principal.logonType === 3 // Interactive
25
+ && principal.runLevel === 0; // Limited
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.97-beta.14",
3
+ "version": "0.6.97-beta.16",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",
@@ -18,6 +18,13 @@
18
18
  "publishConfig": {
19
19
  "access": "public"
20
20
  },
21
+ "scripts": {
22
+ "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
23
+ "build": "tsc -p tsconfig.json",
24
+ "prepublishOnly": "pnpm build && node ../scripts/daemon-release-artifact.mjs --strict-registry",
25
+ "test": "vitest run",
26
+ "typecheck": "tsc --noEmit"
27
+ },
21
28
  "dependencies": {
22
29
  "@agentclientprotocol/sdk": "1.2.1",
23
30
  "@nowcrew/cli": "0.4.17",
@@ -39,11 +46,5 @@
39
46
  "tsx": "^4.19.0",
40
47
  "typescript": "^5.6.0",
41
48
  "vitest": "^2.1.0"
42
- },
43
- "scripts": {
44
- "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
45
- "build": "tsc -p tsconfig.json",
46
- "test": "vitest run",
47
- "typecheck": "tsc --noEmit"
48
49
  }
49
- }
50
+ }