@nowcrew/daemon 0.6.16 → 0.6.17
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/runtime-context.js +7 -1
- package/dist/atomic-private-write.js +54 -1
- package/dist/automatic-install-target.js +40 -11
- package/dist/console.js +9 -0
- package/dist/control-plane-url.js +2 -2
- package/dist/daemon-migration-controller.js +198 -0
- package/dist/daemon-migration-wiring.js +22 -0
- package/dist/daemon-update-eligibility.js +1 -1
- package/dist/directory-projection-identity.js +32 -0
- package/dist/directory-projection.js +922 -0
- package/dist/execution-protocol.js +78 -11
- package/dist/execution-runner.js +50 -2
- package/dist/i18n.js +1 -0
- package/dist/local-execution-prompt.js +57 -0
- package/dist/local-executor.js +99 -40
- package/dist/machine-info.js +45 -9
- package/dist/normalize.js +5 -0
- package/dist/profile-layout.js +41 -0
- package/dist/project-skills/controller.js +74 -14
- package/dist/project-skills/execution-adapter.js +11 -0
- package/dist/project-skills/initialized-reconciler.js +20 -0
- package/dist/project-skills/projection-set-switch.js +419 -0
- package/dist/project-skills/projection-state-domain.js +153 -0
- package/dist/project-skills/projection-state-store.js +841 -0
- package/dist/project-skills/projection-state-transaction.js +318 -0
- package/dist/project-skills/projection-state.js +3 -0
- package/dist/project-skills/reconciler.js +299 -68
- package/dist/project-skills/runtime-warning.js +6 -0
- package/dist/project-skills/scanner.js +30 -1
- package/dist/project-skills/types.js +9 -0
- package/dist/project-workspaces/resolver.js +179 -0
- package/dist/project-workspaces/types.js +1 -0
- package/dist/prompt.js +40 -0
- package/dist/runtimes/claude.js +235 -4
- package/dist/runtimes/codex-app-server-runner.js +92 -23
- package/dist/runtimes/codex-contract.js +123 -0
- package/dist/runtimes/codex.js +2 -0
- package/dist/serve.js +31 -17
- package/dist/session.js +3 -0
- package/dist/supervised-runtime.js +12 -4
- package/dist/workspace.js +14 -5
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { AbilityRepositoryUrlSchema, SafeAbilityPathSchema, WorkspaceAbilityTargetSchema, } from "./agent-ability/types.js";
|
|
3
|
-
import { MAX_AGENT_PROJECT_SKILL_BINDINGS } from "./project-skills/types.js";
|
|
3
|
+
import { compareProjectSkillRefs, MAX_AGENT_PROJECT_SKILL_BINDINGS, MAX_PROJECT_ID_LENGTH, MAX_PROJECT_SKILL_NAME_LENGTH, } from "./project-skills/types.js";
|
|
4
4
|
const ExecutionIdSchema = z.string().uuid();
|
|
5
5
|
const ProtocolVersionSchema = z.literal(1);
|
|
6
6
|
const TimestampSchema = z.string().datetime({ offset: true });
|
|
@@ -20,9 +20,61 @@ export const AgentHandleSchema = z.string().min(1).max(64).refine((handle) => ha
|
|
|
20
20
|
&& !handle.endsWith(" ")
|
|
21
21
|
&& Buffer.byteLength(handle, "utf8") <= 255, "agent handle must be a cross-platform safe filesystem component");
|
|
22
22
|
const ProjectSkillRefSchema = z.object({
|
|
23
|
-
projectId: z.string().min(1).max(
|
|
24
|
-
skillName: z.string().min(1).max(
|
|
23
|
+
projectId: z.string().min(1).max(MAX_PROJECT_ID_LENGTH).regex(/^[a-z0-9][a-z0-9._-]*$/u),
|
|
24
|
+
skillName: z.string().min(1).max(MAX_PROJECT_SKILL_NAME_LENGTH).regex(/^[a-z0-9][a-z0-9._:-]*$/u),
|
|
25
25
|
}).strict();
|
|
26
|
+
const ProjectSkillBindingsSchema = z.array(ProjectSkillRefSchema).max(MAX_AGENT_PROJECT_SKILL_BINDINGS);
|
|
27
|
+
const ProjectSkillProjectionBindingsSchema = ProjectSkillBindingsSchema;
|
|
28
|
+
const ProjectSkillBindingGenerationSchema = z.number().int().min(0).max(MAX_PG_INTEGER);
|
|
29
|
+
function validateCanonicalProjectSkillBindings(bindings, ctx) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (let index = 0; index < bindings.length; index += 1) {
|
|
32
|
+
const binding = bindings[index];
|
|
33
|
+
const key = `${binding.projectId}\0${binding.skillName}`;
|
|
34
|
+
if (seen.has(key)) {
|
|
35
|
+
ctx.addIssue({
|
|
36
|
+
code: z.ZodIssueCode.custom,
|
|
37
|
+
message: "duplicate_project_skill_binding",
|
|
38
|
+
path: ["projectSkills", index],
|
|
39
|
+
});
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
seen.add(key);
|
|
43
|
+
if (index > 0 && compareProjectSkillRefs(bindings[index - 1], binding) > 0) {
|
|
44
|
+
ctx.addIssue({
|
|
45
|
+
code: z.ZodIssueCode.custom,
|
|
46
|
+
message: "project_skill_bindings_not_sorted",
|
|
47
|
+
path: ["projectSkills", index],
|
|
48
|
+
});
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export const ProjectSkillProjectionV2FieldsSchema = z.object({
|
|
54
|
+
projectSkills: ProjectSkillProjectionBindingsSchema,
|
|
55
|
+
projectSkillBindingGeneration: ProjectSkillBindingGenerationSchema,
|
|
56
|
+
}).strict().superRefine((snapshot, ctx) => {
|
|
57
|
+
validateCanonicalProjectSkillBindings(snapshot.projectSkills, ctx);
|
|
58
|
+
});
|
|
59
|
+
const ProjectIdSchema = z.string().min(1).max(64).regex(/^[a-z0-9][a-z0-9._-]*$/u);
|
|
60
|
+
export const ProjectContextSchema = z.object({
|
|
61
|
+
projectIds: z.array(ProjectIdSchema).max(32),
|
|
62
|
+
primaryProjectId: ProjectIdSchema.optional(),
|
|
63
|
+
}).strict().superRefine((value, ctx) => {
|
|
64
|
+
for (let index = 1; index < value.projectIds.length; index += 1) {
|
|
65
|
+
if (value.projectIds[index] === value.projectIds[index - 1]) {
|
|
66
|
+
ctx.addIssue({ code: "custom", message: "duplicate_project_id" });
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
if (value.projectIds[index] < value.projectIds[index - 1]) {
|
|
70
|
+
ctx.addIssue({ code: "custom", message: "project_ids_not_sorted" });
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (value.primaryProjectId && !value.projectIds.includes(value.primaryProjectId)) {
|
|
75
|
+
ctx.addIssue({ code: "custom", message: "primary_project_not_bound" });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
26
78
|
export const AbilityReleaseSnapshotSchema = z.object({
|
|
27
79
|
bindingId: z.string().uuid(),
|
|
28
80
|
releaseId: z.string().uuid(),
|
|
@@ -107,21 +159,36 @@ export const ExecutionAttachmentSchema = z.object({
|
|
|
107
159
|
mime: z.string().min(1).max(200),
|
|
108
160
|
sizeBytes: z.number().int().nonnegative().max(25 * 1024 * 1024),
|
|
109
161
|
}).strict();
|
|
162
|
+
const ExecutionAgentSchema = z.object({
|
|
163
|
+
id: z.string().min(1),
|
|
164
|
+
handle: AgentHandleSchema,
|
|
165
|
+
memoryEnabled: z.boolean().optional(),
|
|
166
|
+
memoryAgentId: z.string().regex(/^agt-[A-Za-z0-9_-]+$/).max(100).optional(),
|
|
167
|
+
projectSkills: ProjectSkillBindingsSchema.optional(),
|
|
168
|
+
projectSkillBindingGeneration: ProjectSkillBindingGenerationSchema.optional(),
|
|
169
|
+
abilityRelease: AbilityReleaseSnapshotSchema.optional(),
|
|
170
|
+
}).strict().superRefine((agent, ctx) => {
|
|
171
|
+
if (agent.projectSkillBindingGeneration === undefined)
|
|
172
|
+
return;
|
|
173
|
+
if (agent.projectSkills === undefined) {
|
|
174
|
+
ctx.addIssue({
|
|
175
|
+
code: z.ZodIssueCode.custom,
|
|
176
|
+
message: "project_skill_generation_requires_bindings",
|
|
177
|
+
path: ["projectSkillBindingGeneration"],
|
|
178
|
+
});
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
validateCanonicalProjectSkillBindings(agent.projectSkills, ctx);
|
|
182
|
+
});
|
|
110
183
|
export const ExecutionStartSchema = z.object({
|
|
111
184
|
type: z.literal("execution:start"),
|
|
112
185
|
protocolVersion: ProtocolVersionSchema,
|
|
113
186
|
executionId: ExecutionIdSchema,
|
|
114
|
-
agent:
|
|
115
|
-
id: z.string().min(1),
|
|
116
|
-
handle: AgentHandleSchema,
|
|
117
|
-
memoryEnabled: z.boolean().optional(),
|
|
118
|
-
memoryAgentId: z.string().regex(/^agt-[A-Za-z0-9_-]+$/).max(100).optional(),
|
|
119
|
-
projectSkills: z.array(ProjectSkillRefSchema).max(MAX_AGENT_PROJECT_SKILL_BINDINGS).optional(),
|
|
120
|
-
abilityRelease: AbilityReleaseSnapshotSchema.optional(),
|
|
121
|
-
}).strict(),
|
|
187
|
+
agent: ExecutionAgentSchema,
|
|
122
188
|
workspace: z.object({
|
|
123
189
|
taskKey: z.string().min(1).max(200),
|
|
124
190
|
resumeKey: z.string().min(1).max(200).optional(),
|
|
191
|
+
projectContext: ProjectContextSchema.optional(),
|
|
125
192
|
}).strict(),
|
|
126
193
|
instructions: z.object({
|
|
127
194
|
language: z.enum(["zh", "en"]),
|
package/dist/execution-runner.js
CHANGED
|
@@ -14,6 +14,10 @@ import { readBoundImDecisionFile, resetBoundImDecisionFile } from "./bound-im-de
|
|
|
14
14
|
import { RuntimeCancelledError } from "./runtime-cancellation.js";
|
|
15
15
|
import { supervisorLaunch } from "./supervised-runtime.js";
|
|
16
16
|
import { appendAgentMemoryContext } from "./agent-memory/policy.js";
|
|
17
|
+
import { projectSkillExecutionProjection, projectSkillProjectionErrorCode } from "./project-skills/execution-adapter.js";
|
|
18
|
+
import { createProjectRegistry } from "./project-skills/registry.js";
|
|
19
|
+
import { ProjectContextUnavailableError, resolveProjectContext } from "./project-workspaces/resolver.js";
|
|
20
|
+
import { PROJECT_WORKSPACES_CAPABILITY } from "./machine-info.js";
|
|
17
21
|
export { supervisorLaunch } from "./supervised-runtime.js";
|
|
18
22
|
const ACTIVITY_KIND = {
|
|
19
23
|
init: "working",
|
|
@@ -41,6 +45,15 @@ function canonical(value) {
|
|
|
41
45
|
export function hashExecutionSpec(spec) {
|
|
42
46
|
return createHash("sha256").update(JSON.stringify(canonical(spec))).digest("hex");
|
|
43
47
|
}
|
|
48
|
+
/** Hashes logical identities only; local project roots are deliberately outside the encoding. */
|
|
49
|
+
export function projectSessionContextFingerprint(runtime, projectContext) {
|
|
50
|
+
const encoded = JSON.stringify(canonical({
|
|
51
|
+
runtime,
|
|
52
|
+
primaryProjectId: projectContext.primaryProjectId ?? null,
|
|
53
|
+
projectIds: [...new Set(projectContext.projectIds)].sort(),
|
|
54
|
+
}));
|
|
55
|
+
return createHash("sha256").update(encoded, "utf8").digest("hex");
|
|
56
|
+
}
|
|
44
57
|
async function reportBestEffort(report, frame, timeoutMs) {
|
|
45
58
|
let timeout;
|
|
46
59
|
try {
|
|
@@ -201,6 +214,15 @@ function rejection(executionId, reason, message, at) {
|
|
|
201
214
|
at,
|
|
202
215
|
});
|
|
203
216
|
}
|
|
217
|
+
export function projectWorkspaceCapabilityRejection(spec, capabilities, at) {
|
|
218
|
+
const projectContext = spec.workspace.projectContext;
|
|
219
|
+
const nativeRuntime = spec.runtime.name === "codex" || spec.runtime.name === "claude";
|
|
220
|
+
return projectContext !== undefined
|
|
221
|
+
&& projectContext.projectIds.length > 0
|
|
222
|
+
&& (!nativeRuntime || !capabilities?.includes(PROJECT_WORKSPACES_CAPABILITY))
|
|
223
|
+
? rejection(spec.executionId, "capability_missing", `${PROJECT_WORKSPACES_CAPABILITY} is unavailable`, at)
|
|
224
|
+
: null;
|
|
225
|
+
}
|
|
204
226
|
function admission(spec, config, dependencies, at) {
|
|
205
227
|
const backend = executionBackendCapability(dependencies.platform ?? process.platform);
|
|
206
228
|
if (!backend.supported) {
|
|
@@ -278,12 +300,15 @@ async function cancellable(promise, cancellation) {
|
|
|
278
300
|
}
|
|
279
301
|
function failedCompletion(spec, error, startedAt, finishedAt) {
|
|
280
302
|
const message = error instanceof Error ? error.message : String(error);
|
|
303
|
+
const errorCode = error instanceof ProjectContextUnavailableError
|
|
304
|
+
? error.code
|
|
305
|
+
: projectSkillProjectionErrorCode(error) ?? "local_execution_failed";
|
|
281
306
|
return ExecutionCompletedSchema.parse({
|
|
282
307
|
type: "execution:completed",
|
|
283
308
|
protocolVersion: 1,
|
|
284
309
|
executionId: spec.executionId,
|
|
285
310
|
outcome: "failed",
|
|
286
|
-
errorCode
|
|
311
|
+
errorCode,
|
|
287
312
|
errorMessage: message || "Unknown local execution failure",
|
|
288
313
|
runtime: spec.runtime.name,
|
|
289
314
|
...(spec.runtime.model === undefined ? {} : { model: spec.runtime.model }),
|
|
@@ -308,6 +333,12 @@ export async function runExecution(config, input, dependencies) {
|
|
|
308
333
|
return { kind: "rejected", frame };
|
|
309
334
|
}
|
|
310
335
|
const spec = parsed.data;
|
|
336
|
+
const capabilityRejection = projectWorkspaceCapabilityRejection(spec, dependencies.capabilities, initialAt);
|
|
337
|
+
if (capabilityRejection !== null) {
|
|
338
|
+
const frame = ExecutionRejectedSchema.parse(boundExecutionFrame(capabilityRejection, config.executionLimits.maxEventBytes));
|
|
339
|
+
await dependencies.report(frame);
|
|
340
|
+
return { kind: "rejected", frame };
|
|
341
|
+
}
|
|
311
342
|
const bestEffortTimeoutMs = telemetryDrainTimeout(dependencies.telemetryDrainTimeoutMs);
|
|
312
343
|
const specHash = hashExecutionSpec(spec);
|
|
313
344
|
const replay = await dependencies.journal.get(spec.executionId);
|
|
@@ -415,6 +446,19 @@ export async function runExecution(config, input, dependencies) {
|
|
|
415
446
|
if (dependencies.slot !== undefined) {
|
|
416
447
|
await cancellable(dependencies.slot.ready, dependencies.cancellation);
|
|
417
448
|
}
|
|
449
|
+
let projectContext;
|
|
450
|
+
let sessionContextFingerprint;
|
|
451
|
+
const logicalProjectContext = spec.workspace.projectContext;
|
|
452
|
+
if (logicalProjectContext !== undefined && logicalProjectContext.projectIds.length > 0) {
|
|
453
|
+
const projectSnapshot = {
|
|
454
|
+
projectIds: logicalProjectContext.projectIds,
|
|
455
|
+
...(logicalProjectContext.primaryProjectId === undefined
|
|
456
|
+
? {}
|
|
457
|
+
: { primaryProjectId: logicalProjectContext.primaryProjectId }),
|
|
458
|
+
};
|
|
459
|
+
projectContext = await cancellable(resolveProjectContext(projectSnapshot, dependencies.projectWorkspaceRegistry ?? createProjectRegistry(config.agentsRoot)), dependencies.cancellation);
|
|
460
|
+
sessionContextFingerprint = projectSessionContextFingerprint(spec.runtime.name, projectSnapshot);
|
|
461
|
+
}
|
|
418
462
|
let recalledMemory = "";
|
|
419
463
|
if (spec.agent.memoryEnabled === true && dependencies.agentMemory !== undefined) {
|
|
420
464
|
try {
|
|
@@ -589,9 +633,13 @@ export async function runExecution(config, input, dependencies) {
|
|
|
589
633
|
keyMode: "opaque",
|
|
590
634
|
taskKey: spec.workspace.taskKey,
|
|
591
635
|
...(spec.workspace.resumeKey === undefined ? {} : { resumeKey: spec.workspace.resumeKey }),
|
|
636
|
+
...(sessionContextFingerprint === undefined ? {} : { sessionContextFingerprint }),
|
|
637
|
+
...(projectContext === undefined ? {} : { projectContext }),
|
|
592
638
|
...(spec.context.wakeMessageId === undefined ? {} : { wakeMessageId: spec.context.wakeMessageId }),
|
|
593
639
|
...(spec.context.attachments === undefined ? {} : { attachments: spec.context.attachments }),
|
|
594
|
-
...(spec.agent.projectSkills === undefined
|
|
640
|
+
...(spec.agent.projectSkills === undefined
|
|
641
|
+
? {}
|
|
642
|
+
: { projectSkills: projectSkillExecutionProjection(spec.agent.projectSkills, spec.agent.projectSkillBindingGeneration) }),
|
|
595
643
|
...(spec.agent.abilityRelease === undefined ? {} : { abilityRelease: spec.agent.abilityRelease }),
|
|
596
644
|
maxSystemPromptBytes: systemPromptBudget,
|
|
597
645
|
systemPrompt: boundedSystemPrompt,
|
package/dist/i18n.js
CHANGED
|
@@ -18,6 +18,7 @@ export function detectDaemonLang(env = process.env) {
|
|
|
18
18
|
const zh = {
|
|
19
19
|
"Claude session started": "Claude 会话启动",
|
|
20
20
|
"Codex session started": "Codex 会话启动",
|
|
21
|
+
"Plan updated": "计划更新",
|
|
21
22
|
"Files changed": "文件变更",
|
|
22
23
|
"Run failed": "运行出错",
|
|
23
24
|
"Run finished": "本轮结束",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 本机执行提示词的合成与预算裁剪。
|
|
3
|
+
*
|
|
4
|
+
* server 提示词是权威部分,绝不裁剪;项目工作区提示词是绑定执行的强制部分,放不下就直接失败;
|
|
5
|
+
* 只有本机事实(CREW_HOME / work-log / MEMORY 注入)是可选增强,按整段丢弃或按字节截断。
|
|
6
|
+
*/
|
|
7
|
+
import { buildRuntimeWorkspacePrompt, capMemoryForInject, capWorkLogForInject, } from "./prompt.js";
|
|
8
|
+
export function truncateUtf8(value, maxBytes) {
|
|
9
|
+
if (maxBytes <= 0)
|
|
10
|
+
return "";
|
|
11
|
+
let bytes = 0;
|
|
12
|
+
let end = 0;
|
|
13
|
+
for (const character of value) {
|
|
14
|
+
const size = Buffer.byteLength(character, "utf8");
|
|
15
|
+
if (bytes + size > maxBytes)
|
|
16
|
+
break;
|
|
17
|
+
bytes += size;
|
|
18
|
+
end += character.length;
|
|
19
|
+
}
|
|
20
|
+
return value.slice(0, end);
|
|
21
|
+
}
|
|
22
|
+
function takeCompletePromptSections(sections, maxBytes) {
|
|
23
|
+
return sections.reduce((state, section) => {
|
|
24
|
+
if (!state.full)
|
|
25
|
+
return state;
|
|
26
|
+
const sectionBytes = Buffer.byteLength(section, "utf8");
|
|
27
|
+
if (state.bytes + sectionBytes > maxBytes)
|
|
28
|
+
return { ...state, full: false };
|
|
29
|
+
return { value: `${state.value}${section}`, bytes: state.bytes + sectionBytes, full: true };
|
|
30
|
+
}, { value: "", bytes: 0, full: true }).value;
|
|
31
|
+
}
|
|
32
|
+
/** v1 server instructions opt in to daemon-owned paths and bounded local workspace context. */
|
|
33
|
+
export function withLocalExecutionFacts(serverPrompt, maxBytes) {
|
|
34
|
+
return ({ workspace, resuming, projectContext }) => {
|
|
35
|
+
const memory = capMemoryForInject(workspace.memory);
|
|
36
|
+
const workLog = resuming ? "" : capWorkLogForInject(workspace.workLog);
|
|
37
|
+
const mandatoryWorkspacePrompt = buildRuntimeWorkspacePrompt(projectContext);
|
|
38
|
+
const localFactSections = [`\n\n## Local execution facts
|
|
39
|
+
- $CREW_HOME: ${workspace.dir}
|
|
40
|
+
- $CREW_TASK_LOG: ${workspace.workLogPath}`,
|
|
41
|
+
...(memory ? [`\n\n## Injected MEMORY.md (bounded local context)\n${memory}`] : []),
|
|
42
|
+
...(workLog ? [`\n\n## Injected work-log (bounded local context)\n${workLog}`] : []),
|
|
43
|
+
];
|
|
44
|
+
const localFacts = localFactSections.join("");
|
|
45
|
+
if (mandatoryWorkspacePrompt !== "") {
|
|
46
|
+
const serverPromptBytes = Buffer.byteLength(serverPrompt, "utf8");
|
|
47
|
+
const mandatoryBytes = Buffer.byteLength(mandatoryWorkspacePrompt, "utf8");
|
|
48
|
+
const requiredBytes = serverPromptBytes + mandatoryBytes;
|
|
49
|
+
if (requiredBytes > maxBytes)
|
|
50
|
+
throw new Error("project_workspace_prompt_budget_exceeded");
|
|
51
|
+
const optionalFacts = takeCompletePromptSections(localFactSections, maxBytes - requiredBytes);
|
|
52
|
+
return `${serverPrompt}${optionalFacts}${mandatoryWorkspacePrompt}`;
|
|
53
|
+
}
|
|
54
|
+
const remaining = maxBytes - Buffer.byteLength(serverPrompt, "utf8");
|
|
55
|
+
return `${serverPrompt}${truncateUtf8(localFacts, remaining)}`;
|
|
56
|
+
};
|
|
57
|
+
}
|
package/dist/local-executor.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createInterface } from "node:readline";
|
|
|
2
2
|
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
3
3
|
import { delimiter, join } from "node:path";
|
|
4
4
|
import { prepareWorkspace, rotateAgentSession, safeKey, } from "./workspace.js";
|
|
5
|
-
import { spawnClaude } from "./runtimes/claude.js";
|
|
5
|
+
import { CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV, isClaudeAdditionalDirectoryInstructionsSupported, probeClaudeVersion, resolveOrderedUniqueClaudeDirectories, spawnClaude, } from "./runtimes/claude.js";
|
|
6
6
|
import { spawnCodex } from "./runtimes/codex.js";
|
|
7
7
|
import { DEEPSEEK_CODEX_MODEL, DEEPSEEK_CODEX_REASONING_LEVELS, materializeDeepSeekCodexHome, } from "./runtimes/codex-deepseek-config.js";
|
|
8
8
|
import { spawnKimi, KIMI_EFFORT_LEVELS } from "./runtimes/kimi.js";
|
|
@@ -11,7 +11,8 @@ import { augmentedPath } from "./runtime-path.js";
|
|
|
11
11
|
import { extractFinalText, extractRunMeta, normalizeEvent, parseLine, } from "./normalize.js";
|
|
12
12
|
import { readSession, writeSession, pickResumeId, isNearBudget } from "./session.js";
|
|
13
13
|
import { createConsoleFormatter } from "./console-formatter.js";
|
|
14
|
-
import {
|
|
14
|
+
import { withLocalExecutionFacts, } from "./local-execution-prompt.js";
|
|
15
|
+
export { withLocalExecutionFacts, } from "./local-execution-prompt.js";
|
|
15
16
|
import { decodeExternalOutputEvent, extractExternalAnswer, ExternalAnswerDecoder, stripExternalAnswerMarkers, } from "./external-output.js";
|
|
16
17
|
import { cleanupMaterializedAttachments as cleanupAttachments, executionAttachmentDirectory, materializeAttachments, } from "./attachments.js";
|
|
17
18
|
import { routeRuntimeAttachments, runtimeCapability, } from "./runtime-capabilities.js";
|
|
@@ -19,6 +20,7 @@ import { awaitWithCancellation, RuntimeCancelledError, } from "./runtime-cancell
|
|
|
19
20
|
import { isRuntimeReadyEvent, } from "./runtime-startup-gate.js";
|
|
20
21
|
import { dslog } from "./slog.js";
|
|
21
22
|
import { boundedDiagnosticJsonArray } from "./diagnostic-json.js";
|
|
23
|
+
import { formatProjectSkillRuntimeWarning } from "./project-skills/runtime-warning.js";
|
|
22
24
|
import { diffMemoryPruneNotes, evaluateMemoryPrunePostcondition, inspectMemoryPruneFilesWithinDeadline, parseMemoryPruneTraceId, } from "./memory-prune-diagnostics.js";
|
|
23
25
|
import { createLocalMemoryTelemetry, logLocalMemoryContextPrepareFailure, logLocalMemoryDiagnosticsFailure, } from "./local-memory-telemetry.js";
|
|
24
26
|
import { CodexStartupStageParser } from "./codex-startup-stage.js";
|
|
@@ -53,39 +55,10 @@ function logMemoryPruneDiagnosticsFailure(input, traceId, phase, error) {
|
|
|
53
55
|
error_code: errorCode,
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
|
-
function truncateUtf8(value, maxBytes) {
|
|
57
|
-
if (maxBytes <= 0)
|
|
58
|
-
return "";
|
|
59
|
-
let bytes = 0;
|
|
60
|
-
let end = 0;
|
|
61
|
-
for (const character of value) {
|
|
62
|
-
const size = Buffer.byteLength(character, "utf8");
|
|
63
|
-
if (bytes + size > maxBytes)
|
|
64
|
-
break;
|
|
65
|
-
bytes += size;
|
|
66
|
-
end += character.length;
|
|
67
|
-
}
|
|
68
|
-
return value.slice(0, end);
|
|
69
|
-
}
|
|
70
|
-
/** v1 server instructions opt in to daemon-owned paths and bounded local workspace context. */
|
|
71
|
-
export function withLocalExecutionFacts(serverPrompt, maxBytes) {
|
|
72
|
-
return ({ workspace, resuming }) => {
|
|
73
|
-
const memory = capMemoryForInject(workspace.memory);
|
|
74
|
-
const workLog = resuming ? "" : capWorkLogForInject(workspace.workLog);
|
|
75
|
-
const localFacts = `\n\n## Local execution facts
|
|
76
|
-
- $CREW_HOME: ${workspace.dir}
|
|
77
|
-
- $CREW_TASK_LOG: ${workspace.workLogPath}${memory
|
|
78
|
-
? `\n\n## Injected MEMORY.md (bounded local context)\n${memory}`
|
|
79
|
-
: ""}${workLog
|
|
80
|
-
? `\n\n## Injected work-log (bounded local context)\n${workLog}`
|
|
81
|
-
: ""}`;
|
|
82
|
-
const remaining = maxBytes - Buffer.byteLength(serverPrompt, "utf8");
|
|
83
|
-
return `${serverPrompt}${truncateUtf8(localFacts, remaining)}`;
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
58
|
const STDERR_TAIL_CAP = 2_000;
|
|
87
59
|
const MEMORY_PRUNE_DIAGNOSTICS_TIMEOUT_MS = 2_000;
|
|
88
60
|
const LOCAL_MEMORY_DIAGNOSTICS_TIMEOUT_MS = 250;
|
|
61
|
+
const CLAUDE_INSTRUCTION_WARNING = "claude_additional_directory_instructions_unverified";
|
|
89
62
|
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
90
63
|
const RESERVED_ENV = new Set([
|
|
91
64
|
"PATH",
|
|
@@ -95,6 +68,16 @@ const RESERVED_ENV = new Set([
|
|
|
95
68
|
"GH_CONFIG_DIR",
|
|
96
69
|
"CLOUDSDK_CONFIG",
|
|
97
70
|
]);
|
|
71
|
+
function withoutClaudeInstructionFlag(env) {
|
|
72
|
+
if (!(CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV in env))
|
|
73
|
+
return env;
|
|
74
|
+
const next = { ...env };
|
|
75
|
+
delete next[CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV];
|
|
76
|
+
return next;
|
|
77
|
+
}
|
|
78
|
+
const warnRuntimeLocally = (code) => {
|
|
79
|
+
process.stderr.write(`[runtime-warning] ${code}\n`);
|
|
80
|
+
};
|
|
98
81
|
export function sanitizeEnvVars(raw) {
|
|
99
82
|
if (!raw)
|
|
100
83
|
return {};
|
|
@@ -155,14 +138,15 @@ async function launchLegacyRuntime(request) {
|
|
|
155
138
|
...(request.reasoning === undefined ? {} : { reasoning: request.reasoning }),
|
|
156
139
|
};
|
|
157
140
|
if (request.runtime === "claude") {
|
|
141
|
+
const additionalDirectories = request.claudeAdditionalDirectories
|
|
142
|
+
?? (request.agentRoot === undefined
|
|
143
|
+
? undefined
|
|
144
|
+
: [join(request.agentRoot, ".crew", "claude-skills"), request.agentRoot]);
|
|
158
145
|
return wrapChild(spawnClaude({
|
|
159
146
|
...common,
|
|
160
147
|
systemPromptPath: request.systemPromptPath,
|
|
161
148
|
wakePrompt: request.wakePrompt,
|
|
162
|
-
...(
|
|
163
|
-
projectSkillsDirectory: join(request.agentRoot, ".crew", "claude-skills"),
|
|
164
|
-
agentRootDirectory: request.agentRoot,
|
|
165
|
-
}),
|
|
149
|
+
...(additionalDirectories === undefined ? {} : { additionalDirectories }),
|
|
166
150
|
...(request.sessionId === undefined ? {} : {
|
|
167
151
|
sessionId: request.sessionId,
|
|
168
152
|
resume: request.resume,
|
|
@@ -221,6 +205,7 @@ export async function executeLocal(input, callbacks = {}, dependencies = {}) {
|
|
|
221
205
|
input.handle,
|
|
222
206
|
input.keyMode ?? "legacy",
|
|
223
207
|
input.resumeKey ?? input.taskKey ?? "",
|
|
208
|
+
...(input.sessionContextFingerprint === undefined ? [] : [input.sessionContextFingerprint]),
|
|
224
209
|
]);
|
|
225
210
|
return withKeyedLease(leaseKey, () => executeLocalUnlocked(input, callbacks, dependencies), dependencies.cancellation);
|
|
226
211
|
}
|
|
@@ -247,6 +232,9 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
247
232
|
...(input.keyMode === undefined ? {} : { keyMode: input.keyMode }),
|
|
248
233
|
...(input.taskKey === undefined ? {} : { taskKey: input.taskKey }),
|
|
249
234
|
...(input.resumeKey === undefined ? {} : { resumeKey: input.resumeKey }),
|
|
235
|
+
...(input.sessionContextFingerprint === undefined
|
|
236
|
+
? {}
|
|
237
|
+
: { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
250
238
|
...(input.launch.description ? { description: input.launch.description } : {}),
|
|
251
239
|
}), dependencies.cancellation);
|
|
252
240
|
}
|
|
@@ -278,9 +266,13 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
278
266
|
}
|
|
279
267
|
const supportsNativeResume = runtime.name === "claude"
|
|
280
268
|
|| (dependencies.launchRuntime !== undefined && runtimeCapability(runtime.name).nativeResume);
|
|
281
|
-
const
|
|
269
|
+
const storedCurrentPrior = input.session.enabled && supportsNativeResume
|
|
282
270
|
? await readSession(workspace.sessionDir)
|
|
283
271
|
: null;
|
|
272
|
+
const currentPrior = storedCurrentPrior !== null
|
|
273
|
+
&& storedCurrentPrior.sessionContextFingerprint === input.sessionContextFingerprint
|
|
274
|
+
? storedCurrentPrior
|
|
275
|
+
: null;
|
|
284
276
|
// Interactive V1 uses collision-resistant session directories, while the
|
|
285
277
|
// older legacy path stored metadata under tasks/<safe thread key>. Import
|
|
286
278
|
// that metadata once so an existing thread can cross the protocol boundary
|
|
@@ -289,6 +281,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
289
281
|
&& supportsNativeResume
|
|
290
282
|
&& input.keyMode === "opaque"
|
|
291
283
|
&& input.resumeKey !== undefined
|
|
284
|
+
&& input.sessionContextFingerprint === undefined
|
|
292
285
|
? join(input.launch.agentsRoot, input.handle, "tasks", safeKey(input.resumeKey))
|
|
293
286
|
: null;
|
|
294
287
|
const legacyCwdMarker = legacyRunDir === null
|
|
@@ -337,6 +330,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
337
330
|
resuming,
|
|
338
331
|
rotatedForBudget,
|
|
339
332
|
nearBudget,
|
|
333
|
+
...(input.projectContext === undefined ? {} : { projectContext: input.projectContext }),
|
|
340
334
|
};
|
|
341
335
|
const systemPrompt = resolvePrompt(input.systemPrompt, promptContext);
|
|
342
336
|
if (input.attachments && input.attachments.length > 0) {
|
|
@@ -442,6 +436,7 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
442
436
|
CREW_TOKEN: input.launch.token,
|
|
443
437
|
CREW_CHANNEL: input.channelId,
|
|
444
438
|
CREW_HOME: workspace.dir,
|
|
439
|
+
CREW_TASK_DIR: executionWorkspace.runDir,
|
|
445
440
|
CREW_TASK_LOG: executionWorkspace.workLogPath,
|
|
446
441
|
...(input.wakeMessageId ? { CREW_WAKE_MESSAGE_ID: input.wakeMessageId } : {}),
|
|
447
442
|
XDG_CONFIG_HOME: join(workspace.homeDir, ".config"),
|
|
@@ -520,15 +515,61 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
520
515
|
skill_count: abilityContext.skillCount,
|
|
521
516
|
});
|
|
522
517
|
}
|
|
518
|
+
const codexSkillRoots = runtime.name === "codex" && input.projectContext !== undefined
|
|
519
|
+
? [
|
|
520
|
+
...(input.projectSkills === undefined
|
|
521
|
+
? []
|
|
522
|
+
: [join(workspace.dir, ".agents", "skills")]),
|
|
523
|
+
...(abilityContext?.skillRoot === undefined ? [] : [abilityContext.skillRoot]),
|
|
524
|
+
]
|
|
525
|
+
: [];
|
|
526
|
+
const claudeAdditionalDirectories = runtime.name === "claude"
|
|
527
|
+
? input.projectContext === undefined
|
|
528
|
+
? abilityContext?.skillRoot === undefined
|
|
529
|
+
? []
|
|
530
|
+
: await resolveOrderedUniqueClaudeDirectories([
|
|
531
|
+
join(workspace.dir, ".crew", "claude-skills"),
|
|
532
|
+
workspace.dir,
|
|
533
|
+
abilityContext.skillRoot,
|
|
534
|
+
])
|
|
535
|
+
: await resolveOrderedUniqueClaudeDirectories([
|
|
536
|
+
...input.projectContext.secondary.map((project) => project.root),
|
|
537
|
+
...(input.projectSkills === undefined
|
|
538
|
+
? []
|
|
539
|
+
: [join(workspace.dir, ".crew", "claude-skills")]),
|
|
540
|
+
...(abilityContext?.skillRoot === undefined ? [] : [abilityContext.skillRoot]),
|
|
541
|
+
], input.projectContext.primary === undefined ? [] : [input.projectContext.primary.root])
|
|
542
|
+
: [];
|
|
543
|
+
let runtimeEnv = childEnv;
|
|
544
|
+
if (runtime.name === "claude"
|
|
545
|
+
&& input.projectContext !== undefined
|
|
546
|
+
&& claudeAdditionalDirectories.length > 0) {
|
|
547
|
+
const version = await (dependencies.probeClaudeVersion ?? probeClaudeVersion)(runtime.name, childEnv)
|
|
548
|
+
.catch(() => null);
|
|
549
|
+
if (isClaudeAdditionalDirectoryInstructionsSupported(version)) {
|
|
550
|
+
runtimeEnv = {
|
|
551
|
+
...childEnv,
|
|
552
|
+
[CLAUDE_ADDITIONAL_DIRECTORY_INSTRUCTIONS_ENV]: "1",
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
runtimeEnv = withoutClaudeInstructionFlag(childEnv);
|
|
557
|
+
(dependencies.warnRuntime ?? warnRuntimeLocally)(CLAUDE_INSTRUCTION_WARNING);
|
|
558
|
+
callbacks.onConsole?.({
|
|
559
|
+
stream: "system",
|
|
560
|
+
text: `[runtime-warning] ${CLAUDE_INSTRUCTION_WARNING}`,
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
}
|
|
523
564
|
const launchRequest = {
|
|
524
565
|
runtime: runtime.name,
|
|
525
566
|
bin: runtime.name === "deepseek-harness" ? "dsh-acp-demo" : runtime.name,
|
|
526
|
-
cwd: executionWorkspace.runDir,
|
|
567
|
+
cwd: input.projectContext?.primary?.root ?? executionWorkspace.runDir,
|
|
527
568
|
...(input.projectSkills === undefined && input.abilityRelease === undefined ? {} : { agentRoot: workspace.dir }),
|
|
528
569
|
systemPromptPath: workspace.systemPromptPath,
|
|
529
570
|
systemPrompt: effectiveSystemPrompt,
|
|
530
571
|
wakePrompt,
|
|
531
|
-
env:
|
|
572
|
+
env: runtimeEnv,
|
|
532
573
|
effectivePermission: input.effectivePermission,
|
|
533
574
|
...(launchModel === undefined ? {} : { model: launchModel }),
|
|
534
575
|
...(launchReasoning === undefined ? {} : { reasoning: launchReasoning }),
|
|
@@ -537,6 +578,16 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
537
578
|
...(attachmentPlan.nativeImagePaths.length > 0
|
|
538
579
|
? { imagePaths: attachmentPlan.nativeImagePaths }
|
|
539
580
|
: {}),
|
|
581
|
+
...(codexSkillRoots.length === 0
|
|
582
|
+
? {}
|
|
583
|
+
: { codexSkillRoots: Object.freeze(codexSkillRoots) }),
|
|
584
|
+
...(claudeAdditionalDirectories.length === 0
|
|
585
|
+
? {}
|
|
586
|
+
: { claudeAdditionalDirectories }),
|
|
587
|
+
...(input.projectContext === undefined ? {} : {
|
|
588
|
+
workspaceRoots: Object.freeze(input.projectContext.secondary.map((project) => project.root)),
|
|
589
|
+
projectContext: input.projectContext,
|
|
590
|
+
}),
|
|
540
591
|
};
|
|
541
592
|
memoryPruneFailurePhase = "runtime_launch";
|
|
542
593
|
return launchRuntime(launchRequest);
|
|
@@ -545,7 +596,12 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
545
596
|
? dependencies.abilityRelease.prepareAndLaunch(input.launch.agentsRoot, input.handle, input.abilityRelease, launchPreparedRuntime)
|
|
546
597
|
: launchPreparedRuntime();
|
|
547
598
|
const child = input.projectSkills !== undefined && dependencies.projectSkills !== undefined
|
|
548
|
-
? await
|
|
599
|
+
? await (Array.isArray(input.projectSkills)
|
|
600
|
+
? dependencies.projectSkills.prepareAndLaunch(input.launch.agentsRoot, input.handle, input.projectSkills, launchWithAbility)
|
|
601
|
+
: dependencies.projectSkills.prepareAndLaunch(input.launch.agentsRoot, input.handle, input.projectSkills, launchWithAbility, (warning) => callbacks.onConsole?.({
|
|
602
|
+
stream: "system",
|
|
603
|
+
text: formatProjectSkillRuntimeWarning(warning),
|
|
604
|
+
})))
|
|
549
605
|
: await launchWithAbility();
|
|
550
606
|
localMemoryTelemetry?.markRuntimeStarted();
|
|
551
607
|
memoryPruneFailurePhase = "runtime_execution";
|
|
@@ -721,6 +777,9 @@ async function executeLocalUnlocked(input, callbacks, dependencies) {
|
|
|
721
777
|
turns: resuming ? (prior?.turns ?? 0) + 1 : 1,
|
|
722
778
|
model: currentModel,
|
|
723
779
|
providerFingerprint: providerFp,
|
|
780
|
+
...(input.sessionContextFingerprint === undefined
|
|
781
|
+
? {}
|
|
782
|
+
: { sessionContextFingerprint: input.sessionContextFingerprint }),
|
|
724
783
|
lastExitOk: exitCode === 0,
|
|
725
784
|
...(contextTokens === undefined ? {} : { contextTokens }),
|
|
726
785
|
});
|
package/dist/machine-info.js
CHANGED
|
@@ -19,9 +19,15 @@ import { probeHermesAcp } from "./runtimes/hermes.js";
|
|
|
19
19
|
import { probeOpenCodeRun } from "./runtimes/opencode.js";
|
|
20
20
|
import { RUNTIME_HEALTH_PROBE_CAPABILITY } from "./runtime-health.js";
|
|
21
21
|
import { probeDeepSeekHarnessAcp } from "./runtimes/deepseek-harness.js";
|
|
22
|
+
import { daemonHome } from "./computer-profile.js";
|
|
22
23
|
export { executableRuntimes } from "./runtime-capabilities.js";
|
|
23
24
|
const execFileP = promisify(execFile);
|
|
24
|
-
export const
|
|
25
|
+
export const PROJECT_WORKSPACES_CAPABILITY = "project_workspaces_v1";
|
|
26
|
+
export const NATIVE_PROJECT_WORKSPACE_READINESS = Object.freeze({
|
|
27
|
+
resolverReady: true,
|
|
28
|
+
nativeRuntimeAdaptersReady: true,
|
|
29
|
+
});
|
|
30
|
+
export const DAEMON_CAPABILITIES = Object.freeze([
|
|
25
31
|
"scheduled_job_v1",
|
|
26
32
|
"reply_origin_v1",
|
|
27
33
|
"origin_decision_v1",
|
|
@@ -33,17 +39,35 @@ export const DAEMON_CAPABILITIES = [
|
|
|
33
39
|
"execution_agent_memory_policy_v1",
|
|
34
40
|
"execution_agent_memory_mapping_v1",
|
|
35
41
|
"project_skills_v1",
|
|
42
|
+
PROJECT_WORKSPACES_CAPABILITY,
|
|
36
43
|
RUNTIME_HEALTH_PROBE_CAPABILITY,
|
|
37
44
|
"agent_ability_release_v1",
|
|
38
45
|
"agent_ability_workspace_v1",
|
|
39
46
|
"agent_ability_runtime_assets_v1",
|
|
40
|
-
];
|
|
41
|
-
export const daemonCapabilities = (runtimePlatform = process.platform
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
&&
|
|
46
|
-
&&
|
|
47
|
+
]);
|
|
48
|
+
export const daemonCapabilities = (runtimePlatform = process.platform, readiness = NATIVE_PROJECT_WORKSPACE_READINESS) => {
|
|
49
|
+
// Windows stays fail-closed until the native workspace adapter gate is verified on a real host.
|
|
50
|
+
const nativeWorkspacePlatform = runtimePlatform === "darwin" || runtimePlatform === "linux";
|
|
51
|
+
const nativeWorkspaceReady = nativeWorkspacePlatform
|
|
52
|
+
&& readiness.resolverReady
|
|
53
|
+
&& readiness.nativeRuntimeAdaptersReady;
|
|
54
|
+
return Object.freeze(DAEMON_CAPABILITIES.filter((capability) => ((capability !== PROJECT_WORKSPACES_CAPABILITY || nativeWorkspaceReady)
|
|
55
|
+
&& (nativeWorkspacePlatform
|
|
56
|
+
|| (capability !== "project_skills_v1"
|
|
57
|
+
&& capability !== "agent_ability_release_v1"
|
|
58
|
+
&& capability !== "agent_ability_workspace_v1"
|
|
59
|
+
&& capability !== "agent_ability_runtime_assets_v1")))));
|
|
60
|
+
};
|
|
61
|
+
export const daemonCapabilityBindings = (runtimePlatform = process.platform, injectedCapabilities) => {
|
|
62
|
+
const snapshot = injectedCapabilities === undefined
|
|
63
|
+
? daemonCapabilities(runtimePlatform)
|
|
64
|
+
: Object.freeze([...injectedCapabilities]);
|
|
65
|
+
return Object.freeze({
|
|
66
|
+
controlPlaneUrl: snapshot,
|
|
67
|
+
machineHello: snapshot,
|
|
68
|
+
executionRunner: snapshot,
|
|
69
|
+
});
|
|
70
|
+
};
|
|
47
71
|
export const EXECUTION_PROTOCOL = Object.freeze({ min: 1, max: 1 });
|
|
48
72
|
/** 候选 runtime CLI:展示名 → 可执行文件名。 */
|
|
49
73
|
const RUNTIME_BINS = [
|
|
@@ -152,7 +176,19 @@ export async function collectMachineHello(agentsRoot, executionLimits, runtimePl
|
|
|
152
176
|
daemonVersion: daemonVersion(),
|
|
153
177
|
runtimes,
|
|
154
178
|
executionRuntimes,
|
|
155
|
-
capabilities: [
|
|
179
|
+
capabilities: Object.freeze([
|
|
180
|
+
...(dependencies.capabilities ?? daemonCapabilities(runtimePlatform)),
|
|
181
|
+
...additionalCapabilities,
|
|
182
|
+
]),
|
|
183
|
+
...(dependencies.profileName === undefined ? {} : {
|
|
184
|
+
layoutVersion: 1,
|
|
185
|
+
profileName: dependencies.profileName,
|
|
186
|
+
daemonHome: dependencies.daemonHome ?? daemonHome(),
|
|
187
|
+
agentsRoot,
|
|
188
|
+
...(dependencies.profileName.match(/^nw-(?:in|dev)-([a-z0-9][a-z0-9_-]{0,39})$/u)?.[1] === undefined
|
|
189
|
+
? {}
|
|
190
|
+
: { localInstanceName: dependencies.profileName.match(/^nw-(?:in|dev)-([a-z0-9][a-z0-9_-]{0,39})$/u)[1] }),
|
|
191
|
+
}),
|
|
156
192
|
...(backend.supported ? {
|
|
157
193
|
executionProtocol: EXECUTION_PROTOCOL,
|
|
158
194
|
executionLimits: Object.freeze({
|
package/dist/normalize.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* 这是 daemon 的关键职责:前端/server 看到的是"在读历史/领任务/发消息",而非裸 Bash。
|
|
5
5
|
* 纯函数,无 IO,完整单测。
|
|
6
6
|
*/
|
|
7
|
+
import { boundedCodexPlan, codexPlanText } from "./runtimes/codex-contract.js";
|
|
7
8
|
/**
|
|
8
9
|
* Strip /bin/zsh -lc, /bin/sh -c, or /bin/bash -lc shell wrappers (single OR double quotes),
|
|
9
10
|
* including multi-line heredoc forms. [\s\S]+ matches across newlines. Backreference \1 ensures
|
|
@@ -63,6 +64,10 @@ function parseKimiBashCommand(args) {
|
|
|
63
64
|
/** 把一个 stream-json 事件归一化为 0..N 个活动。 */
|
|
64
65
|
export function normalizeEvent(event) {
|
|
65
66
|
const e = (event ?? {});
|
|
67
|
+
if (e.type === "turn.plan.updated") {
|
|
68
|
+
const plan = boundedCodexPlan(e.plan);
|
|
69
|
+
return plan === null ? [] : [{ kind: "tool", label: "计划更新", detail: codexPlanText(plan) }];
|
|
70
|
+
}
|
|
66
71
|
if ((e.type === "kimi.acp.text_delta" || e.type === "hermes.acp.text_delta"
|
|
67
72
|
|| e.type === "deepseek-harness.acp.text_delta"
|
|
68
73
|
|| e.type === "opencode.text_delta") && e.text?.trim()) {
|