@nowcrew/daemon 0.6.77-beta.3 → 0.6.77
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/agent-ability/resolver.js +1 -1
- package/dist/config.js +10 -2
- package/dist/execution-runner.js +6 -3
- package/dist/local-executor.js +2 -0
- package/dist/main.js +20 -12
- package/dist/project-dependencies.js +4 -4
- package/dist/repository-identity.js +2 -0
- package/dist/runner.js +2 -0
- package/dist/storage-layout.js +2 -1
- package/package.json +9 -10
|
@@ -185,7 +185,7 @@ const materializeGit = async (cacheRoot, repositoryUrl, commit, target) => {
|
|
|
185
185
|
await git(["--git-dir", bare, "fetch", "--no-tags", "--prune", "origin", commit]);
|
|
186
186
|
const temp = `${target}.tmp-${randomUUID()}`;
|
|
187
187
|
await rm(temp, { recursive: true, force: true });
|
|
188
|
-
await git(["clone", "--
|
|
188
|
+
await git(["clone", "--shared", bare, temp]);
|
|
189
189
|
await git(["checkout", "--detach", commit], temp);
|
|
190
190
|
await rm(join(temp, ".git"), { recursive: true, force: true });
|
|
191
191
|
await mkdir(dirname(target), { recursive: true });
|
package/dist/config.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** daemon 配置:从 env 读取,解析 crew CLI 路径 (注入给 agent 的 wrapper 用)。 */
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { detectDaemonLang, translateDaemon } from "./i18n.js";
|
|
@@ -134,10 +134,18 @@ export function loadConfig(env = process.env) {
|
|
|
134
134
|
maxFirstOutputWaitMs: positiveIntegerEnv(env, "CREW_EXECUTION_MAX_FIRST_OUTPUT_WAIT_MS", DEFAULT_EXECUTION_LIMITS.maxFirstOutputWaitMs),
|
|
135
135
|
firstOutputGraceMs: positiveIntegerEnv(env, "CREW_EXECUTION_FIRST_OUTPUT_GRACE_MS", DEFAULT_EXECUTION_LIMITS.firstOutputGraceMs),
|
|
136
136
|
});
|
|
137
|
+
const agentsRoot = resolveAgentsRoot(env.CREW_AGENTS_ROOT, homedir());
|
|
138
|
+
const configuredReposRoot = env.NOWWORK_REPOS_ROOT?.trim();
|
|
139
|
+
const reposRoot = configuredReposRoot ? resolve(configuredReposRoot) : undefined;
|
|
140
|
+
const configuredQaReportRoot = env.QA_REPORT_HUB?.trim();
|
|
137
141
|
return {
|
|
138
142
|
serverUrl,
|
|
139
143
|
machineToken,
|
|
140
|
-
agentsRoot
|
|
144
|
+
agentsRoot,
|
|
145
|
+
...(reposRoot === undefined ? {} : { reposRoot }),
|
|
146
|
+
qaReportRoot: configuredQaReportRoot
|
|
147
|
+
? resolve(configuredQaReportRoot)
|
|
148
|
+
: join(dirname(reposRoot ?? agentsRoot), "qa-report-server-v2"),
|
|
141
149
|
cliPath: env.CREW_CLI_PATH ?? defaultCliPath(),
|
|
142
150
|
runtimeBin: env.CREW_RUNTIME ?? "claude",
|
|
143
151
|
codexHomeMode: codexHomeModeEnv(env),
|
package/dist/execution-runner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { join } from "node:path";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { DaemonToServerExecutionFrameSchema, ExecutionCompletedSchema, ExecutionRejectedSchema, ExecutionStartSchema, } from "./execution-protocol.js";
|
|
4
4
|
import { JournalConflictError } from "./execution-journal.js";
|
|
5
5
|
import { boundExecutionFrame } from "./execution-event-limit.js";
|
|
@@ -524,10 +524,11 @@ export async function runExecution(config, input, dependencies) {
|
|
|
524
524
|
if (dependencies.abilityRelease !== undefined) {
|
|
525
525
|
await cancellable(dependencies.abilityRelease.apply(config.agentsRoot, spec.agent.handle, spec.agent.abilityRelease), dependencies.cancellation);
|
|
526
526
|
}
|
|
527
|
+
const reposRoot = config.reposRoot ?? join(config.agentsRoot, "repos");
|
|
527
528
|
const preparedProjectDependencies = await cancellable(dependencies.projectDependencies.prepare({
|
|
528
529
|
trainingRoot: join(config.agentsRoot, spec.agent.handle, "training"),
|
|
529
|
-
reposRoot
|
|
530
|
-
lockRoot: join(
|
|
530
|
+
reposRoot,
|
|
531
|
+
lockRoot: join(dirname(resolve(reposRoot)), ".crew", "project-dependencies"),
|
|
531
532
|
}), dependencies.cancellation);
|
|
532
533
|
trainingProjectContext = Object.freeze({
|
|
533
534
|
projects: Object.freeze(preparedProjectDependencies.map((project) => Object.freeze({
|
|
@@ -862,6 +863,8 @@ export async function runExecution(config, input, dependencies) {
|
|
|
862
863
|
token: credential.token,
|
|
863
864
|
agentId: credential.agentId,
|
|
864
865
|
agentsRoot: config.agentsRoot,
|
|
866
|
+
...(config.reposRoot === undefined ? {} : { reposRoot: config.reposRoot }),
|
|
867
|
+
...(config.qaReportRoot === undefined ? {} : { qaReportRoot: config.qaReportRoot }),
|
|
865
868
|
cliPath: config.cliPath,
|
|
866
869
|
providerConfig,
|
|
867
870
|
codexHomeMode: config.codexHomeMode,
|
package/dist/local-executor.js
CHANGED
|
@@ -466,6 +466,8 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
466
466
|
CREW_TOKEN: input.launch.token,
|
|
467
467
|
CREW_CHANNEL: input.channelId,
|
|
468
468
|
CREW_HOME: workspace.dir,
|
|
469
|
+
...(input.launch.reposRoot === undefined ? {} : { NOWWORK_REPOS_ROOT: input.launch.reposRoot }),
|
|
470
|
+
...(input.launch.qaReportRoot === undefined ? {} : { QA_REPORT_HUB: input.launch.qaReportRoot }),
|
|
469
471
|
// Expose only the training root; ability-specific workspace layout stays
|
|
470
472
|
// owned by the training package rather than the NowWork daemon.
|
|
471
473
|
QA_RUNTIME_ROOT: join(workspace.dir, "training"),
|
package/dist/main.js
CHANGED
|
@@ -117,6 +117,23 @@ async function main() {
|
|
|
117
117
|
}
|
|
118
118
|
const provenance = daemonReleaseProvenance(daemonVersion());
|
|
119
119
|
assertReleaseTagForServerUrl(config.serverUrl, provenance.releaseTag);
|
|
120
|
+
const storageRuntime = values.profile === undefined
|
|
121
|
+
? null
|
|
122
|
+
: await loadStorageRuntime({
|
|
123
|
+
profile: values.profile,
|
|
124
|
+
serverUrl: config.serverUrl,
|
|
125
|
+
userHome: homedir(),
|
|
126
|
+
platform: process.platform,
|
|
127
|
+
environment: process.env,
|
|
128
|
+
});
|
|
129
|
+
const runtimeConfig = storageRuntime === null
|
|
130
|
+
? config
|
|
131
|
+
: Object.freeze({
|
|
132
|
+
...config,
|
|
133
|
+
agentsRoot: storageRuntime.layout.agentItemsRoot,
|
|
134
|
+
reposRoot: storageRuntime.layout.repoRoot,
|
|
135
|
+
qaReportRoot: storageRuntime.layout.qaReportRoot,
|
|
136
|
+
});
|
|
120
137
|
if (cmd === "serve") {
|
|
121
138
|
process.stdout.write(formatDaemonLogLine(`🛰️ crew-daemon v${daemonVersion()} (cli v${cliVersion()}, ${provenance.releaseChannel}/${provenance.releaseTag}) ${td("resident, connecting to")} ${config.serverUrl} ${td("control plane")}...`) + "\n");
|
|
122
139
|
const installation = values.profile === undefined
|
|
@@ -125,15 +142,6 @@ async function main() {
|
|
|
125
142
|
const installationLease = installation === null
|
|
126
143
|
? null
|
|
127
144
|
: await acquireDaemonInstallationLease(installation.npmPrefix);
|
|
128
|
-
const storageRuntime = values.profile === undefined
|
|
129
|
-
? null
|
|
130
|
-
: await loadStorageRuntime({
|
|
131
|
-
profile: values.profile,
|
|
132
|
-
serverUrl: config.serverUrl,
|
|
133
|
-
userHome: homedir(),
|
|
134
|
-
platform: process.platform,
|
|
135
|
-
environment: process.env,
|
|
136
|
-
});
|
|
137
145
|
const migrationRuntime = values.profile === undefined || activeDaemonHome === undefined || storageRuntime !== null
|
|
138
146
|
? { ready: false, reason: "not_legacy_source" }
|
|
139
147
|
: await probeStorageMigrationRuntime({
|
|
@@ -188,7 +196,7 @@ async function main() {
|
|
|
188
196
|
}
|
|
189
197
|
: undefined;
|
|
190
198
|
await runWithDaemonInstallationLease(installationLease, async () => {
|
|
191
|
-
const service = serve(
|
|
199
|
+
const service = serve(runtimeConfig, {
|
|
192
200
|
...(values.profile === undefined ? {} : { profileName: values.profile }),
|
|
193
201
|
...(storageMigration === undefined ? {} : { storageMigration }),
|
|
194
202
|
});
|
|
@@ -209,9 +217,9 @@ async function main() {
|
|
|
209
217
|
gitSha: provenance.gitSha,
|
|
210
218
|
artifactDigest: provenance.artifactDigest,
|
|
211
219
|
...(values.profile === undefined ? {} : { profileName: values.profile }),
|
|
212
|
-
agentsRoot:
|
|
220
|
+
agentsRoot: runtimeConfig.agentsRoot,
|
|
213
221
|
}); // 一次性 run 模式也上报 SLS(runner 里的埋点生效)
|
|
214
|
-
const result = await runAgent(
|
|
222
|
+
const result = await runAgent(runtimeConfig, {
|
|
215
223
|
handle: values.agent,
|
|
216
224
|
channelId: values.channel,
|
|
217
225
|
...(values.wake ? { wake: values.wake } : {}),
|
|
@@ -111,8 +111,8 @@ async function ensureWorktreeExclude(mainRoot) {
|
|
|
111
111
|
const suffix = current.length === 0 || current.endsWith("\n") ? "" : "\n";
|
|
112
112
|
await writeFile(excludePath, current + suffix + ".worktrees\n", "utf8");
|
|
113
113
|
}
|
|
114
|
-
async function ensureMainClone(git, repo, repositoryKey, reposRoot) {
|
|
115
|
-
const mainRoot = resolve(reposRoot,
|
|
114
|
+
async function ensureMainClone(git, repo, repositoryKey, directoryName, reposRoot) {
|
|
115
|
+
const mainRoot = resolve(reposRoot, directoryName);
|
|
116
116
|
if (!isWithin(reposRoot, mainRoot) || await existingAncestorIsSymlink(reposRoot, mainRoot)) {
|
|
117
117
|
throw new ProjectDependencyError("project_dependency_checkout_conflict", "repository path is unsafe", repositoryKey);
|
|
118
118
|
}
|
|
@@ -123,7 +123,7 @@ async function ensureMainClone(git, repo, repositoryKey, reposRoot) {
|
|
|
123
123
|
if (info === null) {
|
|
124
124
|
await mkdir(dirname(mainRoot), { recursive: true });
|
|
125
125
|
try {
|
|
126
|
-
await git.run(["clone",
|
|
126
|
+
await git.run(["clone", repo, mainRoot]);
|
|
127
127
|
}
|
|
128
128
|
catch {
|
|
129
129
|
await rm(mainRoot, { recursive: true, force: true }).catch(() => { });
|
|
@@ -243,7 +243,7 @@ export function createProjectDependencyProvisioner(options = {}) {
|
|
|
243
243
|
for (const { identity, projects } of grouped.values()) {
|
|
244
244
|
try {
|
|
245
245
|
await withProjectDependencyLock(lockRoot, identity.repositoryKey, async () => {
|
|
246
|
-
const mainRoot = await ensureMainClone(git, projects[0].repo, identity.repositoryKey, input.reposRoot);
|
|
246
|
+
const mainRoot = await ensureMainClone(git, projects[0].repo, identity.repositoryKey, identity.directoryName, input.reposRoot);
|
|
247
247
|
const seenVersions = new Set();
|
|
248
248
|
for (const project of projects) {
|
|
249
249
|
const branchSource = project.branch === undefined ? "remote-default" : "manifest";
|
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { AbilityRepositoryUrlSchema } from "./agent-ability/types.js";
|
|
3
3
|
const SCP_REPOSITORY = /^git@([^:]+):(.+)$/u;
|
|
4
4
|
const COMMIT = /^[a-f0-9]{40}$/u;
|
|
5
|
+
const DIRECTORY_HASH_LENGTH = 12;
|
|
5
6
|
function normalizePath(value) {
|
|
6
7
|
const path = value.replace(/^\/+|\/+$/gu, "").replace(/\.git$/iu, "");
|
|
7
8
|
if (!path || path.split("/").some((part) => part.length === 0 || part === "." || part === ".." || part.includes("\\"))) {
|
|
@@ -31,6 +32,7 @@ export function normalizeRepositoryIdentity(repository) {
|
|
|
31
32
|
canonical,
|
|
32
33
|
repositoryKey: `repo-${hash}`,
|
|
33
34
|
displayName,
|
|
35
|
+
directoryName: `${displayName}--${hash.slice(0, DIRECTORY_HASH_LENGTH)}`,
|
|
34
36
|
});
|
|
35
37
|
}
|
|
36
38
|
export function worktreeDirectoryName(branch, resolvedCommit) {
|
package/dist/runner.js
CHANGED
|
@@ -84,6 +84,8 @@ export async function runAgent(config, input, onActivity = defaultPrint, onConso
|
|
|
84
84
|
token: credential.token,
|
|
85
85
|
agentId: credential.agentId,
|
|
86
86
|
agentsRoot: config.agentsRoot,
|
|
87
|
+
...(config.reposRoot === undefined ? {} : { reposRoot: config.reposRoot }),
|
|
88
|
+
...(config.qaReportRoot === undefined ? {} : { qaReportRoot: config.qaReportRoot }),
|
|
87
89
|
cliPath: config.cliPath,
|
|
88
90
|
providerConfig,
|
|
89
91
|
codexHomeMode: config.codexHomeMode,
|
package/dist/storage-layout.js
CHANGED
|
@@ -121,6 +121,7 @@ export function storageLayout(input) {
|
|
|
121
121
|
agentItemsRoot: paths.join(workspaceRoot, "agent-items"),
|
|
122
122
|
daemonRoot: paths.join(workspaceRoot, "daemon"),
|
|
123
123
|
repoRoot: paths.join(workspaceRoot, "repos"),
|
|
124
|
+
qaReportRoot: paths.join(workspaceRoot, "qa-report-server-v2"),
|
|
124
125
|
suiteToolsRoot: paths.join(workspaceRoot, "suite-tools"),
|
|
125
126
|
migrationsRoot: paths.join(persistentRoot, "migrations"),
|
|
126
127
|
runtimeRoot,
|
|
@@ -132,7 +133,7 @@ export function agentStorageRoot(layout, agentId) {
|
|
|
132
133
|
}
|
|
133
134
|
const COMPARABLE_FIELDS = [
|
|
134
135
|
"layoutVersion", "environment", "workspaceId", "persistentRoot", "environmentRoot", "workspaceRoot",
|
|
135
|
-
"agentItemsRoot", "daemonRoot", "repoRoot", "suiteToolsRoot", "migrationsRoot", "runtimeRoot",
|
|
136
|
+
"agentItemsRoot", "daemonRoot", "repoRoot", "qaReportRoot", "suiteToolsRoot", "migrationsRoot", "runtimeRoot",
|
|
136
137
|
];
|
|
137
138
|
export function compareStorageLayout(current, expected) {
|
|
138
139
|
if (current === null || current.layoutVersion !== STORAGE_LAYOUT_VERSION)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowcrew/daemon",
|
|
3
|
-
"version": "0.6.77
|
|
3
|
+
"version": "0.6.77",
|
|
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",
|
|
@@ -44,5 +36,12 @@
|
|
|
44
36
|
"tsx": "^4.19.0",
|
|
45
37
|
"typescript": "^5.6.0",
|
|
46
38
|
"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"
|
|
47
46
|
}
|
|
48
|
-
}
|
|
47
|
+
}
|