feat(artifacts): auto-prepare on session.start and support expectedArtifactDirs
- Register session.start hook to call prepareXWorkmateArtifacts best-effort so subsequent export calls have a ready scope. - Use scope directory birthtime/mtime as a floor for sinceUnixMs when the scope is already prepared, so files written before export are still picked up. - Fall back to scanning params.expectedArtifactDirs (under workspaceRoot) when no scoped candidates are found, so callers can point at ad-hoc output directories.
This commit is contained in:
parent
2695c38612
commit
e03f59c2a4
15
dist/index.js
vendored
15
dist/index.js
vendored
@ -37,6 +37,21 @@ const plugin = {
|
||||
};
|
||||
export default plugin;
|
||||
function register(api) {
|
||||
api.registerHook("session.start", async (event) => {
|
||||
try {
|
||||
const params = scopedGatewayParams(event?.context ?? event);
|
||||
if (params.sessionKey && params.runId) {
|
||||
await prepareXWorkmateArtifacts({
|
||||
params,
|
||||
config: api.config,
|
||||
pluginConfig: api.pluginConfig,
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
// Ignored: best-effort preparation
|
||||
}
|
||||
});
|
||||
api.registerGatewayMethod("xworkmate.artifacts.prepare", async (opts) => {
|
||||
try {
|
||||
const payload = await prepareXWorkmateArtifacts({
|
||||
|
||||
31
dist/src/exportArtifacts.js
vendored
31
dist/src/exportArtifacts.js
vendored
@ -146,17 +146,46 @@ export async function exportXWorkmateArtifacts(input) {
|
||||
if (!scopePrepared && sinceUnixMs > 0) {
|
||||
await fs.mkdir(scopeRoot, { recursive: true });
|
||||
}
|
||||
let effectiveSince = sinceUnixMs;
|
||||
if (scopePrepared && sinceUnixMs > 0) {
|
||||
try {
|
||||
const scopeStat = await fs.stat(scopeRoot);
|
||||
effectiveSince = Math.min(sinceUnixMs, scopeStat.birthtimeMs || scopeStat.mtimeMs);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
const scopedCandidates = (await directoryExists(scopeRoot))
|
||||
? await collectCandidates({
|
||||
scanRoot: scopeRoot,
|
||||
relativeRoot: scopeRoot,
|
||||
sinceUnixMs,
|
||||
sinceUnixMs: effectiveSince,
|
||||
warnSkippedSymlinks: true,
|
||||
warnings,
|
||||
ignoreRules: await loadArtifactIgnoreRules(scopeRoot, warnings),
|
||||
})
|
||||
: [];
|
||||
const candidates = scopedCandidates;
|
||||
const expectedDirs = Array.isArray(params.expectedArtifactDirs)
|
||||
? params.expectedArtifactDirs.map((d) => String(d).trim()).filter(Boolean)
|
||||
: [];
|
||||
if (candidates.length === 0 && expectedDirs.length > 0) {
|
||||
for (const dir of expectedDirs) {
|
||||
const dirPath = path.join(workspaceRoot, safeInputRelativePath(dir, "expectedArtifactDir"));
|
||||
if (await directoryExists(dirPath)) {
|
||||
const dirCandidates = await collectCandidates({
|
||||
scanRoot: dirPath,
|
||||
relativeRoot: workspaceRoot,
|
||||
sinceUnixMs: effectiveSince,
|
||||
warnSkippedSymlinks: true,
|
||||
warnings,
|
||||
ignoreRules: await loadArtifactIgnoreRules(dirPath, warnings),
|
||||
});
|
||||
for (const c of dirCandidates) {
|
||||
candidates.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!scopePrepared && candidates.length === 0) {
|
||||
warnings.push("artifact scope is not prepared for this task run");
|
||||
}
|
||||
|
||||
15
index.ts
15
index.ts
@ -84,6 +84,21 @@ const plugin = {
|
||||
export default plugin;
|
||||
|
||||
function register(api: OpenClawPluginApi) {
|
||||
api.registerHook("session.start", async (event: any) => {
|
||||
try {
|
||||
const params = scopedGatewayParams(event?.context ?? event);
|
||||
if (params.sessionKey && params.runId) {
|
||||
await prepareXWorkmateArtifacts({
|
||||
params,
|
||||
config: api.config,
|
||||
pluginConfig: api.pluginConfig,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// Ignored: best-effort preparation
|
||||
}
|
||||
});
|
||||
|
||||
api.registerGatewayMethod("xworkmate.artifacts.prepare", async (opts: GatewayRequestHandlerOptions) => {
|
||||
try {
|
||||
const payload = await prepareXWorkmateArtifacts({
|
||||
|
||||
@ -243,17 +243,46 @@ export async function exportXWorkmateArtifacts(input: ExportInput): Promise<XWor
|
||||
if (!scopePrepared && sinceUnixMs > 0) {
|
||||
await fs.mkdir(scopeRoot, { recursive: true });
|
||||
}
|
||||
let effectiveSince = sinceUnixMs;
|
||||
if (scopePrepared && sinceUnixMs > 0) {
|
||||
try {
|
||||
const scopeStat = await fs.stat(scopeRoot);
|
||||
effectiveSince = Math.min(sinceUnixMs, scopeStat.birthtimeMs || scopeStat.mtimeMs);
|
||||
} catch {}
|
||||
}
|
||||
const scopedCandidates = (await directoryExists(scopeRoot))
|
||||
? await collectCandidates({
|
||||
scanRoot: scopeRoot,
|
||||
relativeRoot: scopeRoot,
|
||||
sinceUnixMs,
|
||||
sinceUnixMs: effectiveSince,
|
||||
warnSkippedSymlinks: true,
|
||||
warnings,
|
||||
ignoreRules: await loadArtifactIgnoreRules(scopeRoot, warnings),
|
||||
})
|
||||
: [];
|
||||
const candidates = scopedCandidates;
|
||||
const expectedDirs = Array.isArray(params.expectedArtifactDirs)
|
||||
? params.expectedArtifactDirs.map((d: any) => String(d).trim()).filter(Boolean)
|
||||
: [];
|
||||
if (candidates.length === 0 && expectedDirs.length > 0) {
|
||||
for (const dir of expectedDirs) {
|
||||
const dirPath = path.join(workspaceRoot, safeInputRelativePath(dir, "expectedArtifactDir"));
|
||||
if (await directoryExists(dirPath)) {
|
||||
const dirCandidates = await collectCandidates({
|
||||
scanRoot: dirPath,
|
||||
relativeRoot: workspaceRoot,
|
||||
sinceUnixMs: effectiveSince,
|
||||
warnSkippedSymlinks: true,
|
||||
warnings,
|
||||
ignoreRules: await loadArtifactIgnoreRules(dirPath, warnings),
|
||||
});
|
||||
for (const c of dirCandidates) {
|
||||
candidates.push(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!scopePrepared && candidates.length === 0) {
|
||||
warnings.push("artifact scope is not prepared for this task run");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user