feat(FN-4912): complete Step 6 — wire env writes into acquisition
Fusion-Task-Id: FN-4912 Fusion-Task-Lineage: 943d0651-052a-41b5-8069-4c60f4db1ba7
This commit is contained in:
committed by
gsxdsm
parent
a8615ecf6c
commit
c8d01ca80d
@@ -111,6 +111,7 @@ export interface HeartbeatMonitorOptions {
|
|||||||
reflectionService?: AgentReflectionService;
|
reflectionService?: AgentReflectionService;
|
||||||
/** Optional self-improvement service for periodic self-improve injection */
|
/** Optional self-improvement service for periodic self-improve injection */
|
||||||
selfImproveService?: SelfImproveServiceLike;
|
selfImproveService?: SelfImproveServiceLike;
|
||||||
|
secretsStore?: Pick<import("@fusion/core").SecretsStore, "listEnvExportable">;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Options for waking up an agent */
|
/** Options for waking up an agent */
|
||||||
@@ -2397,6 +2398,7 @@ export class HeartbeatMonitor {
|
|||||||
audit,
|
audit,
|
||||||
runContext,
|
runContext,
|
||||||
runInitCommand: false,
|
runInitCommand: false,
|
||||||
|
secretsStore: this.options.secretsStore,
|
||||||
});
|
});
|
||||||
sessionCwd = acquisition.worktreePath;
|
sessionCwd = acquisition.worktreePath;
|
||||||
} catch (worktreeErr) {
|
} catch (worktreeErr) {
|
||||||
|
|||||||
@@ -902,6 +902,7 @@ export interface TaskExecutorOptions {
|
|||||||
/** MessageStore for sending messages to other agents. When provided, executor agents gain fn_send_message capability. */
|
/** MessageStore for sending messages to other agents. When provided, executor agents gain fn_send_message capability. */
|
||||||
messageStore?: import("@fusion/core").MessageStore;
|
messageStore?: import("@fusion/core").MessageStore;
|
||||||
missionStore?: MissionStore;
|
missionStore?: MissionStore;
|
||||||
|
secretsStore?: Pick<import("@fusion/core").SecretsStore, "listEnvExportable">;
|
||||||
onSliceComplete?: (slice: Slice) => void;
|
onSliceComplete?: (slice: Slice) => void;
|
||||||
onStart?: (task: Task, worktreePath: string) => void;
|
onStart?: (task: Task, worktreePath: string) => void;
|
||||||
onComplete?: (task: Task) => void;
|
onComplete?: (task: Task) => void;
|
||||||
@@ -2860,6 +2861,7 @@ export class TaskExecutor {
|
|||||||
createWorktree: this.createWorktree.bind(this),
|
createWorktree: this.createWorktree.bind(this),
|
||||||
runConfiguredCommand,
|
runConfiguredCommand,
|
||||||
taskEnv,
|
taskEnv,
|
||||||
|
secretsStore: this.options.secretsStore,
|
||||||
});
|
});
|
||||||
worktreePath = acquisition.worktreePath;
|
worktreePath = acquisition.worktreePath;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { existsSync } from "node:fs";
|
import { existsSync } from "node:fs";
|
||||||
import { exec } from "node:child_process";
|
import { exec } from "node:child_process";
|
||||||
import { promisify } from "node:util";
|
import { promisify } from "node:util";
|
||||||
import type { RunMutationContext, Settings, Task, TaskStore } from "@fusion/core";
|
import type { RunMutationContext, Settings, Task, TaskStore, SecretsStore } from "@fusion/core";
|
||||||
import { generateWorktreeName, slugify } from "./worktree-names.js";
|
import { generateWorktreeName, slugify } from "./worktree-names.js";
|
||||||
import { resolveTaskWorktreePathForBackend } from "./worktree-paths.js";
|
import { resolveTaskWorktreePathForBackend } from "./worktree-paths.js";
|
||||||
import { hydrateWorktreeDb } from "./worktree-db-hydrate.js";
|
import { hydrateWorktreeDb } from "./worktree-db-hydrate.js";
|
||||||
@@ -32,6 +32,7 @@ import {
|
|||||||
type WorktrunkOpName,
|
type WorktrunkOpName,
|
||||||
} from "./worktrunk-failure-handler.js";
|
} from "./worktrunk-failure-handler.js";
|
||||||
import type { RunAuditor } from "./run-audit.js";
|
import type { RunAuditor } from "./run-audit.js";
|
||||||
|
import { writeSecretsEnvFile } from "./secrets-env-writer.js";
|
||||||
|
|
||||||
const execAsync = promisify(exec);
|
const execAsync = promisify(exec);
|
||||||
|
|
||||||
@@ -48,9 +49,10 @@ export interface AcquireTaskWorktreeOptions {
|
|||||||
settings: Partial<Settings>;
|
settings: Partial<Settings>;
|
||||||
pool?: WorktreePool;
|
pool?: WorktreePool;
|
||||||
logger?: { log: (m: string) => void; warn: (m: string) => void; error?: (m: string) => void };
|
logger?: { log: (m: string) => void; warn: (m: string) => void; error?: (m: string) => void };
|
||||||
audit?: RunAuditor;
|
audit?: Pick<RunAuditor, "git" | "filesystem">;
|
||||||
runContext?: RunMutationContext;
|
runContext?: RunMutationContext;
|
||||||
runInitCommand?: boolean;
|
runInitCommand?: boolean;
|
||||||
|
secretsStore?: Pick<SecretsStore, "listEnvExportable">;
|
||||||
createWorktree?: (
|
createWorktree?: (
|
||||||
branch: string,
|
branch: string,
|
||||||
path: string,
|
path: string,
|
||||||
@@ -153,7 +155,7 @@ async function maybeWarnForeignTaskStartPoint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Promise<AcquireTaskWorktreeResult> {
|
export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Promise<AcquireTaskWorktreeResult> {
|
||||||
const { task, rootDir, store, settings, pool, logger, audit, runContext, createWorktree, runConfiguredCommand, runInitCommand, taskEnv } = opts;
|
const { task, rootDir, store, settings, pool, logger, audit, runContext, createWorktree, runConfiguredCommand, runInitCommand, taskEnv, secretsStore } = opts;
|
||||||
const notifyFallback = async (op: WorktrunkOpName, stderr?: string) => {
|
const notifyFallback = async (op: WorktrunkOpName, stderr?: string) => {
|
||||||
await store.logEntry(task.id, `Worktrunk ${op} failed; continuing with native worktree backend (${stderr ?? "no stderr"})`, undefined, runContext);
|
await store.logEntry(task.id, `Worktrunk ${op} failed; continuing with native worktree backend (${stderr ?? "no stderr"})`, undefined, runContext);
|
||||||
};
|
};
|
||||||
@@ -251,6 +253,7 @@ export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Pro
|
|||||||
if (task.worktree && isResume) {
|
if (task.worktree && isResume) {
|
||||||
logger?.log(`Reusing existing worktree: ${worktreePath}`);
|
logger?.log(`Reusing existing worktree: ${worktreePath}`);
|
||||||
const hydrated = await hydrate(worktreePath);
|
const hydrated = await hydrate(worktreePath);
|
||||||
|
// FN-4912: resume path reuses the prior on-disk .env (and its fingerprint sidecar). Rewrite is owned by the next fresh acquisition.
|
||||||
return { worktreePath, branch: task.branch ?? branchName, source: "existing", hydrated, isResume: true };
|
return { worktreePath, branch: task.branch ?? branchName, source: "existing", hydrated, isResume: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,6 +341,20 @@ export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Pro
|
|||||||
runContext,
|
runContext,
|
||||||
});
|
});
|
||||||
const hydrated = await hydrate(worktreePath);
|
const hydrated = await hydrate(worktreePath);
|
||||||
|
try {
|
||||||
|
await writeSecretsEnvFile({
|
||||||
|
rootDir,
|
||||||
|
worktreePath,
|
||||||
|
taskId: task.id,
|
||||||
|
settings,
|
||||||
|
worktreeSource: "pool",
|
||||||
|
secretsStore,
|
||||||
|
audit,
|
||||||
|
logger,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
logger?.warn?.(`${task.id}: secrets-env write failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
worktreePath,
|
worktreePath,
|
||||||
branch,
|
branch,
|
||||||
@@ -449,5 +466,19 @@ export async function acquireTaskWorktree(opts: AcquireTaskWorktreeOptions): Pro
|
|||||||
runContext,
|
runContext,
|
||||||
});
|
});
|
||||||
const hydrated = await hydrate(worktreePath);
|
const hydrated = await hydrate(worktreePath);
|
||||||
|
try {
|
||||||
|
await writeSecretsEnvFile({
|
||||||
|
rootDir,
|
||||||
|
worktreePath,
|
||||||
|
taskId: task.id,
|
||||||
|
settings,
|
||||||
|
worktreeSource: "fresh",
|
||||||
|
secretsStore,
|
||||||
|
audit,
|
||||||
|
logger,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
logger?.warn?.(`${task.id}: secrets-env write failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
||||||
|
}
|
||||||
return { worktreePath, branch, source: acquiredFromPool ? "pool" : "fresh", hydrated, isResume: false };
|
return { worktreePath, branch, source: acquiredFromPool ? "pool" : "fresh", hydrated, isResume: false };
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user