Diff non-git workspaces via an mtime baseline

`projectBashArtifacts` and `reconcileWorkspaceArtifacts` used to bail
with `not_a_git_repo` whenever the workspace had no `.git`, so bash
output in such workspaces never reached `work_products` and the
DocumentCenter looked empty while files piled up on disk.

`captureWorkspaceBaseline` now walks the workspace at `prepareRun`
time, skipping the same categories the registrability filter rejects
(`.git`, `node_modules`, `.next`, caches) and capping at
`MAX_BASELINE_ENTRIES` so large trees stay bounded. The baseline rides
on `ActiveRunContext.workspaceBaseline` and is passed into every
artifact projection.

`collectChangedPaths` is the single change-detector for both the
per-bash projection and the end-of-run reconciliation. It picks `git
status` when a `.git` is present and falls back to a
`diffAgainstBaseline` walk otherwise. Paths already on the ignore list
still never land in `work_products`; the identity stays
`(company, workspace, provider, externalId)`; the upsert still refreshes
`last_touched_by_run_id` so the deliverable signal follows the latest
touching run.
This commit is contained in:
ZacharyZhang-NY committed 2026-04-19 16:18:25 -04:00
1 parent b1d1fbc54f
commit d4c6056f5e
3 files changed
+218 -57

No files matched your search

+2
View File
@@ -58,6 +58,7 @@ export interface ActiveRunContext {
taskSessionId: string;
workspaceId: string | null;
workspacePath: string | null;
workspaceBaseline: import("./artifact-projector").WorkspaceBaseline | null;
state: ActiveRunLifecycleState;
}
@@ -179,6 +180,7 @@ export function handleAfterToolCall(
taskId: ctx.taskId,
workspaceId: ctx.workspaceId,
workspacePath: ctx.workspacePath,
workspaceBaseline: ctx.workspaceBaseline,
};
try {
const outcomes = projectToolExecutionToWorkProduct(