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;
|
export default plugin;
|
||||||
function register(api) {
|
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) => {
|
api.registerGatewayMethod("xworkmate.artifacts.prepare", async (opts) => {
|
||||||
try {
|
try {
|
||||||
const payload = await prepareXWorkmateArtifacts({
|
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) {
|
if (!scopePrepared && sinceUnixMs > 0) {
|
||||||
await fs.mkdir(scopeRoot, { recursive: true });
|
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))
|
const scopedCandidates = (await directoryExists(scopeRoot))
|
||||||
? await collectCandidates({
|
? await collectCandidates({
|
||||||
scanRoot: scopeRoot,
|
scanRoot: scopeRoot,
|
||||||
relativeRoot: scopeRoot,
|
relativeRoot: scopeRoot,
|
||||||
sinceUnixMs,
|
sinceUnixMs: effectiveSince,
|
||||||
warnSkippedSymlinks: true,
|
warnSkippedSymlinks: true,
|
||||||
warnings,
|
warnings,
|
||||||
ignoreRules: await loadArtifactIgnoreRules(scopeRoot, warnings),
|
ignoreRules: await loadArtifactIgnoreRules(scopeRoot, warnings),
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
const candidates = scopedCandidates;
|
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) {
|
if (!scopePrepared && candidates.length === 0) {
|
||||||
warnings.push("artifact scope is not prepared for this task run");
|
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;
|
export default plugin;
|
||||||
|
|
||||||
function register(api: OpenClawPluginApi) {
|
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) => {
|
api.registerGatewayMethod("xworkmate.artifacts.prepare", async (opts: GatewayRequestHandlerOptions) => {
|
||||||
try {
|
try {
|
||||||
const payload = await prepareXWorkmateArtifacts({
|
const payload = await prepareXWorkmateArtifacts({
|
||||||
|
|||||||
@ -243,17 +243,46 @@ export async function exportXWorkmateArtifacts(input: ExportInput): Promise<XWor
|
|||||||
if (!scopePrepared && sinceUnixMs > 0) {
|
if (!scopePrepared && sinceUnixMs > 0) {
|
||||||
await fs.mkdir(scopeRoot, { recursive: true });
|
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))
|
const scopedCandidates = (await directoryExists(scopeRoot))
|
||||||
? await collectCandidates({
|
? await collectCandidates({
|
||||||
scanRoot: scopeRoot,
|
scanRoot: scopeRoot,
|
||||||
relativeRoot: scopeRoot,
|
relativeRoot: scopeRoot,
|
||||||
sinceUnixMs,
|
sinceUnixMs: effectiveSince,
|
||||||
warnSkippedSymlinks: true,
|
warnSkippedSymlinks: true,
|
||||||
warnings,
|
warnings,
|
||||||
ignoreRules: await loadArtifactIgnoreRules(scopeRoot, warnings),
|
ignoreRules: await loadArtifactIgnoreRules(scopeRoot, warnings),
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
const candidates = scopedCandidates;
|
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) {
|
if (!scopePrepared && candidates.length === 0) {
|
||||||
warnings.push("artifact scope is not prepared for this task run");
|
warnings.push("artifact scope is not prepared for this task run");
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user