@nowcrew/daemon 0.6.79-beta.2 → 0.6.80-beta.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.
@@ -32,6 +32,8 @@ import { diffMemoryPruneNotes, evaluateMemoryPrunePostcondition, inspectMemoryPr
32
32
  import { createLocalMemoryTelemetry, logLocalMemoryContextPrepareFailure, logLocalMemoryDiagnosticsFailure, } from "./local-memory-telemetry.js";
33
33
  import { CodexStartupStageParser } from "./codex-startup-stage.js";
34
34
  import { formatRuntimeStartupError } from "./runtime-startup-error.js";
35
+ import { machinePackageManagerEnv, packageManagerEnvFacts } from "./package-manager-env.js";
36
+ import { sanitizeEnvVars } from "./runtime-env.js";
35
37
  import { commitLocalMemoryResultAfterExit, initializeLocalMemoryV2ForWorkspace, isLocalMemoryV2Eligible, localMemoryResultPath as makeLocalMemoryResultPath, renderLocalMemoryResultInstructions, } from "./local-memory/runtime.js";
36
38
  export class RuntimeRunningCallbackTimeoutError extends Error {
37
39
  constructor(runtime, timeoutMs) {
@@ -49,15 +51,6 @@ const MEMORY_PRUNE_DIAGNOSTICS_TIMEOUT_MS = 2_000;
49
51
  const LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS = 250;
50
52
  const CLAUDE_INSTRUCTION_WARNING = "claude_additional_directory_instructions_unverified";
51
53
  const CODEX_COLLABORATION_EXEC_WARNING = "codex_collaboration_disabled_on_exec";
52
- const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
53
- const RESERVED_ENV = new Set([
54
- "PATH",
55
- "XDG_CONFIG_HOME",
56
- "XDG_DATA_HOME",
57
- "XDG_CACHE_HOME",
58
- "GH_CONFIG_DIR",
59
- "CLOUDSDK_CONFIG",
60
- ]);
61
54
  function withoutClaudeInstructionFlag(env) {
62
55
  if (!(CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV in env))
63
56
  return env;
@@ -68,14 +61,6 @@ function withoutClaudeInstructionFlag(env) {
68
61
  const warnRuntimeLocally = (code) => {
69
62
  process.stderr.write(`[runtime-warning] ${code}\n`);
70
63
  };
71
- export function sanitizeEnvVars(raw) {
72
- if (!raw)
73
- return {};
74
- return Object.fromEntries(Object.entries(raw).filter(([key, value]) => typeof value === "string"
75
- && ENV_KEY_RE.test(key)
76
- && !key.toUpperCase().startsWith("CREW_")
77
- && !RESERVED_ENV.has(key.toUpperCase())));
78
- }
79
64
  export function awaitExit(child) {
80
65
  return new Promise((resolve) => {
81
66
  let settled = false;
@@ -461,6 +446,9 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
461
446
  const baseEnv = {
462
447
  ...inheritedEnv,
463
448
  ...sanitizeEnvVars(providerConfig.envVars),
449
+ ...(input.trainingProjectContext === undefined
450
+ ? {}
451
+ : machinePackageManagerEnv(inheritedEnv)),
464
452
  ...input.launch.systemEnv,
465
453
  PATH: `${workspace.crewDir}${delimiter}${augmentedPath()}`,
466
454
  CREW_SERVER_URL: input.launch.serverUrl,
@@ -503,6 +491,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
503
491
  qa_runtime_root: childEnv.QA_RUNTIME_ROOT ?? null,
504
492
  qa_runtime_root_present: childEnv.QA_RUNTIME_ROOT !== undefined,
505
493
  inherited_qa_runtime_root_present: inheritedEnv.QA_RUNTIME_ROOT !== undefined,
494
+ ...packageManagerEnvFacts(childEnv),
506
495
  training_root: join(workspace.dir, "training"),
507
496
  project_context_present: input.projectContext !== undefined,
508
497
  project_ids: JSON.stringify(input.projectContext === undefined
package/dist/main.js CHANGED
File without changes
@@ -0,0 +1,75 @@
1
+ import { readFileSync } from "node:fs";
2
+ function nonEmpty(value) {
3
+ const normalized = value?.trim();
4
+ return normalized === undefined || normalized === "" ? undefined : normalized;
5
+ }
6
+ function registryUrl(value) {
7
+ const normalized = nonEmpty(value);
8
+ if (normalized === undefined)
9
+ return undefined;
10
+ try {
11
+ const protocol = new URL(normalized).protocol;
12
+ return protocol === "http:" || protocol === "https:" ? normalized : undefined;
13
+ }
14
+ catch {
15
+ return undefined;
16
+ }
17
+ }
18
+ function configuredPath(env) {
19
+ const explicit = env.CREW_PACKAGE_MANAGER_USERCONFIG?.trim();
20
+ if (explicit !== undefined && explicit !== "")
21
+ return explicit;
22
+ return undefined;
23
+ }
24
+ function registryFromNpmrc(path) {
25
+ if (path === undefined)
26
+ return undefined;
27
+ try {
28
+ const line = readFileSync(path, "utf8")
29
+ .split(/\r?\n/u)
30
+ .find((entry) => /^\s*registry\s*=/u.test(entry));
31
+ return registryUrl(line?.replace(/^\s*registry\s*=\s*/u, ""));
32
+ }
33
+ catch {
34
+ return undefined;
35
+ }
36
+ }
37
+ function npmrcHasAuth(path) {
38
+ if (path === undefined)
39
+ return false;
40
+ try {
41
+ return /^\s*(?:(?:\/\/[^=\s]+:)?_(?:auth|authToken|password))\s*=/imu.test(readFileSync(path, "utf8"));
42
+ }
43
+ catch {
44
+ return false;
45
+ }
46
+ }
47
+ /**
48
+ * Keep machine-owned npm credentials available for explicitly authorized
49
+ * training dependency installs. The daemon must opt in with
50
+ * CREW_PACKAGE_MANAGER_USERCONFIG; Agent env cannot reach this path.
51
+ */
52
+ export function machinePackageManagerEnv(env = process.env) {
53
+ const npmUserConfig = configuredPath(env);
54
+ const yarnRegistry = npmUserConfig === undefined
55
+ ? undefined
56
+ : registryUrl(env.YARN_REGISTRY) ?? registryFromNpmrc(npmUserConfig);
57
+ const entries = npmUserConfig === undefined
58
+ ? []
59
+ : [["NPM_CONFIG_USERCONFIG", npmUserConfig]];
60
+ const alwaysAuth = npmrcHasAuth(npmUserConfig) ? "true" : undefined;
61
+ return Object.fromEntries(yarnRegistry === undefined && alwaysAuth === undefined
62
+ ? entries
63
+ : [
64
+ ...entries,
65
+ ...(yarnRegistry === undefined ? [] : [["YARN_REGISTRY", yarnRegistry]]),
66
+ ...(alwaysAuth === undefined ? [] : [["NPM_CONFIG_ALWAYS_AUTH", alwaysAuth]]),
67
+ ]);
68
+ }
69
+ export function packageManagerEnvFacts(env) {
70
+ return {
71
+ npm_userconfig_present: Boolean(env.NPM_CONFIG_USERCONFIG?.trim()),
72
+ yarn_registry_present: Boolean(env.YARN_REGISTRY?.trim()),
73
+ npm_always_auth_present: Boolean(env.NPM_CONFIG_ALWAYS_AUTH?.trim()),
74
+ };
75
+ }
package/dist/runner.js CHANGED
@@ -11,7 +11,8 @@ import { readOriginDecisionFile, resetOriginDecisionFile } from "./origin-decisi
11
11
  import { readBoundImDecisionFile, resetBoundImDecisionFile } from "./bound-im-decision.js";
12
12
  import { launchSupervisedRuntime } from "./supervised-runtime.js";
13
13
  import { awaitWithCancellation, } from "./runtime-cancellation.js";
14
- export { awaitExit, exitActivity, sanitizeEnvVars } from "./local-executor.js";
14
+ export { awaitExit, exitActivity } from "./local-executor.js";
15
+ export { sanitizeEnvVars } from "./runtime-env.js";
15
16
  const ICON = {
16
17
  init: "🟢", text: "💬", reading: "📖", sending: "📨", checking: "🔎",
17
18
  claiming: "📌", crew: "⚙️", tool: "🛠️", tool_result: "↩️", done: "✅", error: "❌",
@@ -0,0 +1,21 @@
1
+ const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
2
+ export const RESERVED_ENV = new Set([
3
+ "PATH",
4
+ "XDG_CONFIG_HOME",
5
+ "XDG_DATA_HOME",
6
+ "XDG_CACHE_HOME",
7
+ "GH_CONFIG_DIR",
8
+ "CLOUDSDK_CONFIG",
9
+ "NPM_CONFIG_USERCONFIG",
10
+ "YARN_REGISTRY",
11
+ "NPM_CONFIG_ALWAYS_AUTH",
12
+ ]);
13
+ /** 用户自定义环境只能补充普通变量,不能覆盖 daemon 维护的运行时契约。 */
14
+ export function sanitizeEnvVars(raw) {
15
+ if (!raw)
16
+ return {};
17
+ return Object.fromEntries(Object.entries(raw).filter(([key, value]) => typeof value === "string"
18
+ && ENV_KEY_RE.test(key)
19
+ && !key.toUpperCase().startsWith("CREW_")
20
+ && !RESERVED_ENV.has(key.toUpperCase())));
21
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.79-beta.2",
3
+ "version": "0.6.80-beta.1",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",
@@ -16,6 +16,14 @@
16
16
  "publishConfig": {
17
17
  "access": "public"
18
18
  },
19
+ "scripts": {
20
+ "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
21
+ "build": "tsc -p tsconfig.json",
22
+ "codex-home:migrate": "tsx src/runtimes/codex-home-migration-cli.ts",
23
+ "prepublishOnly": "pnpm build && node ../scripts/daemon-release-artifact.mjs --strict-registry",
24
+ "test": "vitest run",
25
+ "typecheck": "tsc --noEmit"
26
+ },
19
27
  "dependencies": {
20
28
  "@agentclientprotocol/sdk": "1.2.1",
21
29
  "@nowcrew/cli": "0.4.13",
@@ -36,12 +44,5 @@
36
44
  "tsx": "^4.19.0",
37
45
  "typescript": "^5.6.0",
38
46
  "vitest": "^2.1.0"
39
- },
40
- "scripts": {
41
- "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
42
- "build": "tsc -p tsconfig.json",
43
- "codex-home:migrate": "tsx src/runtimes/codex-home-migration-cli.ts",
44
- "test": "vitest run",
45
- "typecheck": "tsc --noEmit"
46
47
  }
47
- }
48
+ }
@@ -1,109 +0,0 @@
1
- import { PROJECT_SKILLS_CAPABILITY, PROJECT_SKILL_PROJECTION_V2_CAPABILITY, } from "./types.js";
2
- export function projectSkillV2RolloutReady(platform, readiness) {
3
- const platformReady = platform === "darwin"
4
- || platform === "linux"
5
- || (platform === "win32" && readiness.nativeWindowsSmokePassed);
6
- return platformReady
7
- && readiness.runtimeRootStorePrimitiveReady
8
- && readiness.runtimeRootStoreRecoveryReady
9
- && readiness.leaseRecoveryReady
10
- && readiness.controllerReady
11
- && readiness.executionHandlerReady
12
- && readiness.codexAdapterReady
13
- && readiness.claudeAdapterReady;
14
- }
15
- export function effectiveProjectSkillCapabilities(capabilities, projectSkillsReady, projectSkillV2Ready) {
16
- const projectSkillCapabilitiesReady = projectSkillsReady && projectSkillV2Ready;
17
- if (!projectSkillCapabilitiesReady
18
- && !capabilities.includes(PROJECT_SKILLS_CAPABILITY)
19
- && !capabilities.includes(PROJECT_SKILL_PROJECTION_V2_CAPABILITY)
20
- && Object.isFrozen(capabilities))
21
- return capabilities;
22
- const filtered = capabilities.filter((capability) => capability !== PROJECT_SKILL_PROJECTION_V2_CAPABILITY
23
- && (projectSkillCapabilitiesReady || capability !== PROJECT_SKILLS_CAPABILITY));
24
- if (!projectSkillCapabilitiesReady || !filtered.includes(PROJECT_SKILLS_CAPABILITY)) {
25
- return Object.freeze(filtered);
26
- }
27
- const v1Index = filtered.indexOf(PROJECT_SKILLS_CAPABILITY);
28
- return Object.freeze([
29
- ...filtered.slice(0, v1Index + 1),
30
- PROJECT_SKILL_PROJECTION_V2_CAPABILITY,
31
- ...filtered.slice(v1Index + 1),
32
- ]);
33
- }
34
- export function withProjectSkillCapabilityStatus(value, status) {
35
- return {
36
- ...value,
37
- projectSkillsStatus: status,
38
- capabilities: status === "ready"
39
- ? value.capabilities
40
- : effectiveProjectSkillCapabilities(value.capabilities, false, false),
41
- };
42
- }
43
- const settleReadinessGate = async (operation) => {
44
- try {
45
- return await operation() === true;
46
- }
47
- catch {
48
- return false;
49
- }
50
- };
51
- export async function createProjectSkillConnectionCapabilitySnapshot(input) {
52
- const runtimeRootStorePrimitiveReady = await settleReadinessGate(input.probeRuntimeRootStorePrimitive);
53
- const controllerReady = await settleReadinessGate(input.initializeController);
54
- const recoveryReady = await settleReadinessGate(input.recoverRuntimeRootsAndLeases);
55
- const readiness = Object.freeze({
56
- runtimeRootStorePrimitiveReady,
57
- runtimeRootStoreRecoveryReady: recoveryReady,
58
- leaseRecoveryReady: recoveryReady,
59
- controllerReady,
60
- executionHandlerReady: true,
61
- codexAdapterReady: true,
62
- claudeAdapterReady: true,
63
- nativeWindowsSmokePassed: false,
64
- });
65
- const projectSkillsReady = projectSkillV2RolloutReady(input.platform, readiness);
66
- return Object.freeze({
67
- capabilities: effectiveProjectSkillCapabilities(input.baseCapabilities, projectSkillsReady, projectSkillsReady),
68
- projectSkillsReady,
69
- readiness,
70
- });
71
- }
72
- export async function prepareProjectSkillConnectionCapabilities(input) {
73
- const snapshot = await createProjectSkillConnectionCapabilitySnapshot({
74
- ...input,
75
- baseCapabilities: [...input.baseCapabilities, ...await input.additionalCapabilities()],
76
- });
77
- input.applyReadiness(snapshot.projectSkillsReady);
78
- return snapshot.capabilities;
79
- }
80
- export function createProjectSkillControllerReadiness(input) {
81
- let status = "initializing";
82
- let initialization = null;
83
- const ensure = () => {
84
- if (status === "ready")
85
- return Promise.resolve(true);
86
- if (initialization !== null)
87
- return initialization;
88
- status = "initializing";
89
- const attempt = input.initialize().then(() => {
90
- status = "ready";
91
- return true;
92
- }, (error) => {
93
- status = "unavailable";
94
- input.onUnavailable(error);
95
- return false;
96
- }).finally(() => {
97
- if (initialization === attempt)
98
- initialization = null;
99
- input.onSettled();
100
- });
101
- initialization = attempt;
102
- return attempt;
103
- };
104
- return Object.freeze({
105
- status: () => status,
106
- ensure,
107
- applyPreflight: (ready) => { status = ready ? "ready" : "unavailable"; },
108
- });
109
- }
@@ -1,57 +0,0 @@
1
- import { ProjectProjectionError, } from "./reconciler.js";
2
- export const MAX_REMEMBERED_PROJECT_SKILL_AGENTS = 64;
3
- const compareBinary = (left, right) => {
4
- if (left < right)
5
- return -1;
6
- if (left > right)
7
- return 1;
8
- return 0;
9
- };
10
- const copySnapshot = (snapshot) => Object.freeze({
11
- bindings: Object.freeze(snapshot.bindings.map((binding) => Object.freeze({ ...binding }))),
12
- generation: snapshot.generation,
13
- });
14
- export function createProjectSkillSnapshotEpoch(maxEntries = MAX_REMEMBERED_PROJECT_SKILL_AGENTS) {
15
- if (!Number.isSafeInteger(maxEntries) || maxEntries < 1) {
16
- throw new ProjectProjectionError("skill_projection_failed");
17
- }
18
- const snapshots = new Map();
19
- return Object.freeze({
20
- begin() {
21
- snapshots.clear();
22
- },
23
- remember(handle, snapshot) {
24
- const previous = snapshots.get(handle);
25
- if (previous !== undefined && snapshot.generation < previous.generation)
26
- return;
27
- if (previous === undefined && snapshots.size >= maxEntries) {
28
- throw new ProjectProjectionError("skill_projection_failed");
29
- }
30
- snapshots.set(handle, copySnapshot(snapshot));
31
- },
32
- forget(handle) {
33
- snapshots.delete(handle);
34
- },
35
- entries() {
36
- return Object.freeze([...snapshots.entries()]
37
- .sort(([left], [right]) => compareBinary(left, right))
38
- .map(([handle, snapshot]) => Object.freeze([handle, copySnapshot(snapshot)])));
39
- },
40
- });
41
- }
42
- const stableErrorCode = (reason) => reason?.code === "skill_projection_snapshot_corrupt"
43
- ? "skill_projection_snapshot_corrupt"
44
- : "skill_projection_failed";
45
- export function toPathPrivateConvergenceResults(entries, results) {
46
- return Object.freeze(entries.map(([handle], index) => {
47
- const result = results[index];
48
- if (result?.status === "fulfilled") {
49
- return Object.freeze({ handle, status: "fulfilled" });
50
- }
51
- return Object.freeze({
52
- handle,
53
- status: "rejected",
54
- errorCode: stableErrorCode(result?.reason),
55
- });
56
- }));
57
- }