@nowcrew/daemon 0.6.39 → 0.6.40

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.
@@ -501,6 +501,19 @@ export async function runExecution(config, input, dependencies) {
501
501
  let projectContext;
502
502
  let sessionContextFingerprint;
503
503
  const logicalProjectContext = spec.workspace.projectContext;
504
+ dslog("project_dependencies.preflight", "项目依赖准备前置状态", {
505
+ execution_id: spec.executionId,
506
+ agent_handle: spec.agent.handle,
507
+ has_ability_release: spec.agent.abilityRelease !== undefined,
508
+ ability_release_id: spec.agent.abilityRelease?.releaseId,
509
+ ability_root_commit: spec.agent.abilityRelease?.rootCommit,
510
+ has_project_context: logicalProjectContext !== undefined,
511
+ project_ids: JSON.stringify(logicalProjectContext?.projectIds ?? []),
512
+ project_context_primary: logicalProjectContext?.primaryProjectId,
513
+ dependency_prepare_expected: spec.agent.abilityRelease !== undefined
514
+ && logicalProjectContext !== undefined
515
+ && logicalProjectContext.projectIds.length > 0,
516
+ });
504
517
  if (logicalProjectContext !== undefined && logicalProjectContext.projectIds.length > 0) {
505
518
  const projectSnapshot = {
506
519
  projectIds: logicalProjectContext.projectIds,
@@ -532,6 +545,25 @@ export async function runExecution(config, input, dependencies) {
532
545
  });
533
546
  }
534
547
  }
548
+ else if (spec.agent.abilityRelease === undefined) {
549
+ dslog("project_dependencies.skipped", "缺少 abilityRelease,未执行项目依赖准备", {
550
+ level: "WARN",
551
+ execution_id: spec.executionId,
552
+ agent_handle: spec.agent.handle,
553
+ project_ids: JSON.stringify(projectSnapshot.projectIds),
554
+ reason: "ability_release_missing",
555
+ });
556
+ }
557
+ else {
558
+ dslog("project_dependencies.skipped", "Daemon 未提供项目依赖准备器", {
559
+ level: "WARN",
560
+ execution_id: spec.executionId,
561
+ agent_handle: spec.agent.handle,
562
+ project_ids: JSON.stringify(projectSnapshot.projectIds),
563
+ ability_release_id: spec.agent.abilityRelease.releaseId,
564
+ reason: "provisioner_missing",
565
+ });
566
+ }
535
567
  projectContext = await cancellable(resolveProjectContext(projectSnapshot, projectWorkspaceRegistry), dependencies.cancellation);
536
568
  sessionContextFingerprint = projectSessionContextFingerprint(spec.runtime.name, projectSnapshot);
537
569
  }
@@ -491,6 +491,27 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
491
491
  const childEnv = runtime.name === "deepseek-harness"
492
492
  ? applyDeepSeekHarnessMachineEnv(providerEnv, inheritedEnv)
493
493
  : providerEnv;
494
+ dslog("runtime.environment_contract", "Runtime 子进程环境契约", {
495
+ execution_id: input.executionId,
496
+ agent_handle: input.handle,
497
+ runtime: runtime.name,
498
+ qa_runtime_root: childEnv.QA_RUNTIME_ROOT ?? null,
499
+ qa_runtime_root_present: childEnv.QA_RUNTIME_ROOT !== undefined,
500
+ inherited_qa_runtime_root_present: inheritedEnv.QA_RUNTIME_ROOT !== undefined,
501
+ training_root: join(workspace.dir, "training"),
502
+ project_context_present: input.projectContext !== undefined,
503
+ project_ids: JSON.stringify(input.projectContext === undefined
504
+ ? []
505
+ : [
506
+ ...(input.projectContext.primary === undefined
507
+ ? []
508
+ : [input.projectContext.primary.projectId]),
509
+ ...input.projectContext.secondary.map((project) => project.projectId),
510
+ ]),
511
+ ability_release_present: input.abilityRelease !== undefined,
512
+ ability_release_id: input.abilityRelease?.releaseId,
513
+ ability_root_commit: input.abilityRelease?.rootCommit,
514
+ });
494
515
  const launchRuntime = dependencies.launchRuntime ?? launchLegacyRuntime;
495
516
  if (dependencies.cancellation?.isRequested())
496
517
  throw new RuntimeCancelledError();
package/dist/main.js CHANGED
File without changes
@@ -4,6 +4,7 @@ import { dirname, join, resolve, sep } from "node:path";
4
4
  import { promisify } from "node:util";
5
5
  import { parse } from "yaml";
6
6
  import { validateAbilityGitHost } from "./agent-ability/resolver.js";
7
+ import { dslog } from "./slog.js";
7
8
  import { PROJECT_BRANCH, PROJECT_BRANCH_FORBIDDEN, PROJECT_MANIFEST_SOURCE_PATH, ProjectDependencyManifestSchema, } from "./project-dependency-manifest.js";
8
9
  const runFile = promisify(execFile);
9
10
  const PROJECT_MANIFEST_RELATIVE_PATH = PROJECT_MANIFEST_SOURCE_PATH;
@@ -130,12 +131,19 @@ async function checkoutProject(git, project, branch, target) {
130
131
  }
131
132
  }
132
133
  try {
133
- return {
134
- resolvedCommit: await git.run(["rev-parse", "HEAD"], target),
135
- created,
136
- };
134
+ if (project.commit !== undefined) {
135
+ await git.run(["checkout", "--force", "--detach", project.commit], target);
136
+ }
137
+ const resolvedCommit = await git.run(["rev-parse", "HEAD"], target);
138
+ if (project.commit !== undefined && resolvedCommit !== project.commit) {
139
+ throw new ProjectDependencyError("project_dependency_commit_mismatch", `project ${project.id} resolved to an unexpected commit`, project.id);
140
+ }
141
+ return { resolvedCommit, created };
137
142
  }
138
143
  catch {
144
+ if (project.commit !== undefined) {
145
+ throw new ProjectDependencyError("project_dependency_commit_mismatch", `project ${project.id} could not be checked out at the requested commit`, project.id);
146
+ }
139
147
  throw new ProjectDependencyError("project_dependency_checkout_failed", "checkout commit cannot be resolved", project.id);
140
148
  }
141
149
  }
@@ -195,8 +203,17 @@ export function createProjectDependencyProvisioner(options) {
195
203
  return {
196
204
  async prepare(input) {
197
205
  const manifest = await readProjectManifest(input.trainingRoot);
198
- if (manifest === null || input.projectIds.length === 0)
206
+ dslog("project_dependencies.manifest", "读取项目依赖清单", {
207
+ training_root: input.trainingRoot,
208
+ manifest_present: manifest !== null,
209
+ requested_project_ids: JSON.stringify(input.projectIds),
210
+ declared_project_ids: JSON.stringify(manifest?.projects.map((project) => project.id) ?? []),
211
+ });
212
+ if (input.projectIds.length === 0)
199
213
  return Object.freeze([]);
214
+ if (manifest === null) {
215
+ throw new ProjectDependencyError("project_dependency_manifest_missing", "project dependency manifest is missing from the active training package");
216
+ }
200
217
  if (!isWithin(input.trainingRoot, projectManifestPath(input.trainingRoot))) {
201
218
  throw new ProjectDependencyError("project_dependency_manifest_invalid", "project manifest path escapes training root");
202
219
  }
@@ -237,6 +254,7 @@ export function createProjectDependencyProvisioner(options) {
237
254
  repo: project.repo,
238
255
  branch,
239
256
  branchSource,
257
+ ...(project.commit === undefined ? {} : { requestedCommit: project.commit }),
240
258
  resolvedCommit: checkout.resolvedCommit,
241
259
  checkoutMode: "shared",
242
260
  localRoot: root,
@@ -5,10 +5,12 @@ export const PROJECT_MANIFEST_SOURCE_PATH = "workspace/project-dependencies.yaml
5
5
  export const PROJECT_BRANCH = /^[A-Za-z0-9][A-Za-z0-9._/-]{0,255}$/u;
6
6
  export const PROJECT_BRANCH_FORBIDDEN = /(?:^|\/)\.\.?(?:\/|$)|[\s\p{Cc}\\]/u;
7
7
  export const PROJECT_SUMMARY_MAX_LENGTH = 1_000;
8
+ export const PROJECT_COMMIT = /^[a-f0-9]{40}$/u;
8
9
  const ProjectDependencySchema = z.object({
9
10
  id: z.string().min(1).max(64),
10
11
  repo: AbilityRepositoryUrlSchema,
11
12
  branch: z.string().min(1).max(256).optional(),
13
+ commit: z.string().optional(),
12
14
  summary: z.string().min(1).max(PROJECT_SUMMARY_MAX_LENGTH),
13
15
  }).strict().superRefine((project, ctx) => {
14
16
  if (!isProjectId(project.id)) {
@@ -18,6 +20,9 @@ const ProjectDependencySchema = z.object({
18
20
  && (!PROJECT_BRANCH.test(project.branch) || PROJECT_BRANCH_FORBIDDEN.test(project.branch))) {
19
21
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["branch"], message: "invalid project branch" });
20
22
  }
23
+ if (project.commit !== undefined && !PROJECT_COMMIT.test(project.commit)) {
24
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["commit"], message: "invalid project commit" });
25
+ }
21
26
  });
22
27
  export const ProjectDependencyManifestSchema = z.object({
23
28
  version: z.literal(1),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nowcrew/daemon",
3
- "version": "0.6.39",
3
+ "version": "0.6.40",
4
4
  "type": "module",
5
5
  "description": "crew daemon — 运行在用户机器:拉起/管理 agent 进程,注入 crew CLI,归一化 runtime 事件",
6
6
  "license": "Apache-2.0",
@@ -16,14 +16,6 @@
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
- },
27
19
  "dependencies": {
28
20
  "@agentclientprotocol/sdk": "1.2.1",
29
21
  "@nowcrew/cli": "^0.4.13",
@@ -42,5 +34,12 @@
42
34
  "tsx": "^4.19.0",
43
35
  "typescript": "^5.6.0",
44
36
  "vitest": "^2.1.0"
37
+ },
38
+ "scripts": {
39
+ "daemon": "pnpm --filter @nowcrew/cli build && tsx src/main.ts",
40
+ "build": "tsc -p tsconfig.json",
41
+ "codex-home:migrate": "tsx src/runtimes/codex-home-migration-cli.ts",
42
+ "test": "vitest run",
43
+ "typecheck": "tsc --noEmit"
45
44
  }
46
- }
45
+ }