feat: sync existing workspace directory artifacts recursively
This commit is contained in:
parent
fcc579e679
commit
7bf9ed4e40
@ -792,7 +792,17 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
}
|
||||
final bytes = bytesResult.bytes;
|
||||
if (bytes == null) {
|
||||
skippedArtifact = true;
|
||||
final existingArtifactPaths =
|
||||
await _existingWorkspaceArtifactPathsInternal(root, relativePath);
|
||||
if (existingArtifactPaths.isEmpty) {
|
||||
skippedArtifact = true;
|
||||
continue;
|
||||
}
|
||||
wroteArtifact = true;
|
||||
_appendArtifactRelativePathsInternal(
|
||||
currentTaskArtifactRelativePaths,
|
||||
existingArtifactPaths,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
final target = await _nextArtifactTargetFileInternal(root, relativePath);
|
||||
@ -813,7 +823,10 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
target.path,
|
||||
);
|
||||
if (writtenRelativePath != null && writtenRelativePath.isNotEmpty) {
|
||||
currentTaskArtifactRelativePaths.add(writtenRelativePath);
|
||||
_appendArtifactRelativePathsInternal(
|
||||
currentTaskArtifactRelativePaths,
|
||||
<String>[writtenRelativePath],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1145,6 +1158,57 @@ extension AppControllerDesktopRuntimeHelpers on AppController {
|
||||
) => kGatewayRemoteProfileIndex;
|
||||
}
|
||||
|
||||
void _appendArtifactRelativePathsInternal(
|
||||
List<String> target,
|
||||
List<String> paths,
|
||||
) {
|
||||
for (final path in paths) {
|
||||
if (!target.contains(path)) {
|
||||
target.add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<String>> _existingWorkspaceArtifactPathsInternal(
|
||||
Directory root,
|
||||
String relativePath,
|
||||
) async {
|
||||
final targetPath = DesktopThreadArtifactService.resolveAbsolutePathInternal(
|
||||
root.path,
|
||||
relativePath,
|
||||
);
|
||||
final targetType = await FileSystemEntity.type(
|
||||
targetPath,
|
||||
followLinks: false,
|
||||
);
|
||||
if (targetType == FileSystemEntityType.file) {
|
||||
final resolvedRelativePath =
|
||||
DesktopThreadArtifactService.relativePathInternal(
|
||||
root.path,
|
||||
targetPath,
|
||||
);
|
||||
return resolvedRelativePath == null || resolvedRelativePath.isEmpty
|
||||
? const <String>[]
|
||||
: <String>[resolvedRelativePath];
|
||||
}
|
||||
if (targetType != FileSystemEntityType.directory) {
|
||||
return const <String>[];
|
||||
}
|
||||
final files = await DesktopThreadArtifactService().collectFilesInternal(
|
||||
Directory(targetPath),
|
||||
);
|
||||
final paths = <String>[];
|
||||
for (final file in files) {
|
||||
final resolvedRelativePath =
|
||||
DesktopThreadArtifactService.relativePathInternal(root.path, file.path);
|
||||
if (resolvedRelativePath != null && resolvedRelativePath.isNotEmpty) {
|
||||
paths.add(resolvedRelativePath);
|
||||
}
|
||||
}
|
||||
paths.sort();
|
||||
return paths;
|
||||
}
|
||||
|
||||
String _normalizeAuthorizationHeaderInternal(String raw) {
|
||||
final trimmed = raw.trim();
|
||||
if (trimmed.isEmpty) {
|
||||
|
||||
@ -589,6 +589,88 @@ void main() {
|
||||
},
|
||||
);
|
||||
|
||||
test('syncs existing workspace directory artifacts recursively', () async {
|
||||
final controller = AppController(
|
||||
environmentOverride: const <String, String>{},
|
||||
);
|
||||
addTearDown(controller.dispose);
|
||||
|
||||
final localWorkspace = await Directory.systemTemp.createTemp(
|
||||
'xworkmate-recursive-artifact-workspace-',
|
||||
);
|
||||
addTearDown(() async {
|
||||
if (await localWorkspace.exists()) {
|
||||
await localWorkspace.delete(recursive: true);
|
||||
}
|
||||
});
|
||||
await Directory(
|
||||
'${localWorkspace.path}/assets/images/chapters',
|
||||
).create(recursive: true);
|
||||
await File(
|
||||
'${localWorkspace.path}/assets/images/cover.png',
|
||||
).writeAsBytes(<int>[1, 2, 3]);
|
||||
await File(
|
||||
'${localWorkspace.path}/assets/images/chapters/chapter-1.png',
|
||||
).writeAsBytes(<int>[4, 5, 6]);
|
||||
await File(
|
||||
'${localWorkspace.path}/chapters/codex-chapter-breakdown.md',
|
||||
).create(recursive: true);
|
||||
|
||||
controller.upsertTaskThreadInternal(
|
||||
'unit-fixture-task-a',
|
||||
workspaceBinding: WorkspaceBinding(
|
||||
workspaceId: 'unit-fixture-task-a',
|
||||
workspaceKind: WorkspaceKind.localFs,
|
||||
workspacePath: localWorkspace.path,
|
||||
displayPath: localWorkspace.path,
|
||||
writable: true,
|
||||
),
|
||||
);
|
||||
|
||||
final result = GoTaskServiceResult(
|
||||
success: true,
|
||||
message: 'generated files',
|
||||
turnId: 'turn-recursive',
|
||||
raw: <String, dynamic>{
|
||||
'artifacts': <Map<String, dynamic>>[
|
||||
<String, dynamic>{'relativePath': 'assets/images/'},
|
||||
<String, dynamic>{
|
||||
'relativePath': 'chapters/codex-chapter-breakdown.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
errorMessage: '',
|
||||
resolvedModel: '',
|
||||
route: GoTaskServiceRoute.externalAcpSingle,
|
||||
);
|
||||
|
||||
await controller.persistGoTaskArtifactsForSessionInternal(
|
||||
'unit-fixture-task-a',
|
||||
result,
|
||||
);
|
||||
|
||||
final thread = controller.requireTaskThreadForSessionInternal(
|
||||
'unit-fixture-task-a',
|
||||
);
|
||||
expect(thread.lastArtifactSyncStatus, 'synced');
|
||||
expect(thread.lastTaskArtifactRelativePaths, <String>[
|
||||
'assets/images/chapters/chapter-1.png',
|
||||
'assets/images/cover.png',
|
||||
'chapters/codex-chapter-breakdown.md',
|
||||
]);
|
||||
final snapshot = await controller.loadAssistantArtifactSnapshot(
|
||||
sessionKey: 'unit-fixture-task-a',
|
||||
);
|
||||
expect(
|
||||
snapshot.resultEntries.map((entry) => entry.relativePath),
|
||||
containsAll(<String>[
|
||||
'assets/images/chapters/chapter-1.png',
|
||||
'assets/images/cover.png',
|
||||
'chapters/codex-chapter-breakdown.md',
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
test(
|
||||
'downloads bridge URL artifacts into the local thread workspace',
|
||||
() async {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user